后端
创建模型类
规格模型类和规格选项模型类
规格模型类外键绑定spu表
规格选项类绑定规格表
# 规格模型类定义
class SPUSpec(models.Model):
name=models.CharField('规格名称',max_length=20)
spu=models.ForeignKey(SPUS,on_delete=models.CASCADE,verbose_name='所属spu')
def __str__(self):
return self.name
class Meta:
db_table='spu_spec'
verbose_name_plural='spu的规格'
# 规格选项模型类定义
class SpecOption(models.Model):
value=models.CharField('选项值',max_length=20)
spec=models.ForeignKey(SPUSpec,on_delete=models.CASCADE,verbose_name='规格名称')
def __str__(self):
return '%s:%s-%s'%(self.spec.spu.name,self.spec.name,self.value)
class Meta:
db_table='spec_option'
verbose_name_plural='规格选项值'
编写序列化器
#SPU规格模型类的序列化器
class SPUSpecSer(serializers.ModelSerializer):
spu_name=serializers.SerializerMethodField(read_only=True)
def get_spu_name(self,obj):
return obj.spu.name
class Meta:
model=SPUSpec
fields='__all__'
read_only_fields=['id']
#SPU模型类的序列化器---简洁版
class SPUSerSimple(serializers.ModelSerializer):
class Meta:
model=SPUS
fields=["id","name"]
read_only_fields=['id','name']
# 规格选项值模型类的序列化器
class SpecOptionSer(serializers.ModelSerializer):
spec_name=serializers.SerializerMethodField(read_only=True)
def get_spec_name(self,obj):
return obj.spec.name
class Meta:
model=SpecOption
fields='__all__'
read_only_fields=['id']
编写视图类
#规格的视图
class SPUSpecView(ModelViewSet):
queryset = SPUSpec.objects.all()
serializer_class = SPUSpecSer
lookup_field = 'pk'
lookup_url_kwarg = 'pk'
pagination_class = MyPagination
#spu简化的视图 避免分页器导致数据显示不全
class SPUAllAPIView(ModelViewSet):
queryset = SPUS.objects.all()
serializer_class = SPUSerSimple
#规格选项值的视图
class SpecOptionViewSet(ModelViewSet):
queryset = SpecOption.objects.all()
serializer_class = SpecOptionSer
lookup_field = 'pk'
lookup_url_kwarg = 'pk'
pagination_class = MyPagination
#加载所有的规格spuSpec 避免分页器导致数据不全
class SPUSpecAllAPIView(ListAPIView):
queryset = SPUSpec.objects.all()
serializer_class = SPUSpecSer
配置路由
from django.urls import path
from rest_framework import routers
from .views import *
urlpatterns = [
#加载所有的规格spuSpec 避免分页器导致数据不全
path('spuSpecs/all/',SPUSpecAllAPIView.as_view())
]
#品牌的路由
router=routers.SimpleRouter()
router.register('spusall',SPUAllAPIView) #spu简化的路由
router.register('spuSpecs',SPUSpecView,'spuSpecs') #规格的路由
router.register('specOption',SpecOptionViewSet,'specOption') #规格选项路由
urlpatterns+=router.urls
前端
找到对应的veu组件,进行配置
实现规格的增删改查
例如:Specs.vue 获取全部数据
<script>
import BreadCrumb from '@/components/widget/BreadCrumb'
//添加规格
import AddSpecs from '@/components/widget/AddSpecs'
//展示 删除 修改 规格
import SpecsTable from '@/components/widget/SpecsTable'
// import cons from '@/components/constant'
export default {
name: 'Specs',
data () {
return {
page:1,
total:0,
pagesize:3,
aSpecsList:[]
}
},
components:{
BreadCrumb,
AddSpecs,
SpecsTable
},
mounted(){
this.fnGetData(1);
},
methods:{
fnGetData(num){
this.axios.get('/v1/goods/spuSpecs/',{
params:{
page:num ? num :this.page,
pageSize:this.pagesize
},
headers:{
Authorization:'JWT '+localStorage.token
},
responseType:'json'
}).then((result) => {
console.log("111111111111111111",result)
this.aSpecsList=result.data.results
this.total=result.data.count
}).catch((err) => {
console.log('err:',err)
});
},
//分页的时间函数
fnGetPage(num){
this.page=num
this.fnGetData(num)a
}
}
}
</script>
例如:SpecsTable.vue进行展示修改数据
修改事件中的路由,字段等
<script>
let token = localStorage.token;
export default {
name: 'AuthorityTable',
props:['specs'],
data () {
var validateName = (rule, value, callback) => {
if (value === '') {
callback(new Error('规格名不能为空'));
} else {
callback()
}
};
return {
pop_show:false,
edit_id:'',
spus_list:[],
specsForm:{
name:'',
spu:''
},
rulesSpecsForm:{
name: [
{ validator:validateName, trigger: 'blur' }
]
}
}
},
methods:{
// 点击编辑触发的方法
fnPopShow(id){
this.pop_show = true;
this.edit_id = id;
this.axios.get('/v1/goods/spuSpecs/'+this.edit_id+'/', {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json',
})
.then(res=>{
this.specsForm.name = res.data.name;
this.specsForm.spu = res.data.spu;
}).catch(err=>{
console.log('获取错误的信息',err);
});
},
// 提交
submitForm(){
this.axios.put('/v1/goods/spuSpecs/'+this.edit_id+'/', {
"name": this.specsForm.name,
"spu": this.specsForm.spu,
}, {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json'
}).then(res=>{
this.$message({
type: 'success',
message: '修改规格成功!'
});
this.pop_show = false;
this.$emit('fnResetTable');
this.resetForm('specsForm');
}).catch(err=>{
console.log(err.response);
})
},
fnDelSpecs(id){
this.edit_id = id;
this.$confirm('此操作将删除该规格, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.delete('/v1/goods/spuSpecs/'+this.edit_id+'/',{
headers: {
'Authorization': 'JWT ' + token
},
responseType:'json'
}).then(res=>{
if (res.status==204){
this.$message({
type: 'success',
message: '删除成功!'
});
this.$emit('fnResetTable');
}else{
this.$message({
type:'error',
message:'删除失败'
})
}
}).catch(err=>{
if(err.response.status==404){
this.$message({
type:'info',
message:'规格未找到!'
});
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
// 获取所有的spu数据
fnGetSPUs(){
this.axios.get('/v1/goods/spusall/', {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json',
})
.then(res=>{
this.spus_list = res.data;
}).catch(err=>{
console.log(err.response);
});
},
resetForm(formName){
this.$refs[formName].resetFields();
}
},
mounted(){
this.fnGetSPUs();
}
}
</script>
例如:AddSpecs.vue进行修改数据
修改事件中的路由,字段等
添加绑定外键的字段实现下拉框添加
添加跟修改获取数据类似
<script>
let token = localStorage.token;
export default {
name: 'AddUser',
data () {
var validateName = (rule, value, callback) => {
if (value === '') {
callback(new Error('规格名不能为空'));
} else {
callback()
}
};
return {
pop_show:false,
spus_list:[],
specsForm:{
name:'',
spu_id:''
},
rulesSpecsForm:{
name: [
{ validator:validateName, trigger: 'blur' }
]
}
}
},
methods:{
submitForm(){
// console.log("spu_id<<<<<",this.specsForm.spu_id)
this.axios.post('/v1/goods/spuSpecs/', {
"name":this.specsForm.name,
"spu":this.specsForm.spu_id
}, {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json'
})
.then(res=>{
if(res.status==201){
this.$message({
type: 'success',
message: '添加规格成功!'
});
this.pop_show = false;
this.$emit('fnResetTable');
this.resetForm('spcesForm');
}
}).catch(err=>{
if(err.response){
var errmsg = err.response.data;
if(errmsg.name){
this.$message({
type:'info',
message:errmsg.name[0]
});
}
if(errmsg.non_field_errors){
this.$message({
type:'info',
message:errmsg.non_field_errors[0]
});
}
}
});
},
//获取所有spu数据
fnGetGoods(){
this.axios.get('/v1/goods/spusall/', {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json',
})
.then(res=>{
this.spus_list = res.data;
}).catch(err=>{
console.log(err.response);
});
},
resetForm(formName){
this.$refs[formName].resetFields();
}
},
mounted(){
this.fnGetGoods();
}
}
</script>
规格选项跟上边的类似,找到对应的vue组件即可实现