大家好,这里是<测试开发实战-手把手系列之四>
在上一节中我们创建了product(产品)应用,讲这一节前我们先创建一个project(组件)应用,基本框架与product一致,过程不再详细说明。
前面说过,项目的结构是1个product对应多个project,1个project有多个product使用,所以product和project的对应关系是多对多,这样就需要一个关联表product_project来保存他们的对应关系。
我们创建一个ProductProject应用来专门处理他们之间的关联
看一下ProductProject应用的model.py
model.py
import ...
class ProductProjectModel(models.Model):
id = models.IntegerField(primary_key=True, db_column='id')
product_id = models.IntegerField(max_length=11)
project_id = models.IntegerField(max_length=11)
class Meta:
db_table = "product_project"
可以看到,上面的字段与数据库的字段是对应的,但与我们实际使用是不契合的。比如前端想展示product和project的对应关系并显示名称,根据上面model的结构,我只能得到是product_id和project_id
显然,这不是我想要的,我真正想要的是所有的product_id和project _id对应的product和project对象,这里,就用到了外键(ForeignKey)这个东西。
我们改造一下
model.py改
from django.db import models
from product.model import productModel
from project.models import projectModel
class ProductProjectModel(models.Model):
id = models.IntegerField(primary_key=True, db_column='id')
product_id = models.IntegerField
project_id = models.IntegerField
project = models.ForeignKey(projectModel, related_name='ProductProject_project', on_delete=models.CASCADE) # 关联外键
product = models.ForeignKey(productModel, related_name='ProductProject_product', on_delete=models.CASCADE) # 关联外键
class Meta:
db_table = "product_project"
重点:
1、ForeignKey:外键关键字
2、related_name:子表在主表中对应的外键属性,需保证唯一性
3、on_delete: 删除关联表(project)中的数据时,当前表(ProductProject)与其关联的field的行为
这样我们就把project用外键关联起来了,我们调一下ProductProject.SelectAll接口
呵呵,没起作用,查看SelectAll代码,发现使用的是object.values()方法
#查询所有
class SelectAll(View):
def post(self, request):
listRes = ProductProjectModel.objects.values()
listRes = list(listRes)
return HttpResponse(json.dumps({"modelList": listRes, "code": 20000}, cls=DateEncoder),
content_type="application/json")
改成all()方法,调接口,结果报错了
TypeError: Object of type ProductProjectModel is not JSON serializable
提示对象类型不能json序列化
object.values()和object.all()的区别请参考上一节
OK,到了这里,就来到本节重头了,为了解决这个问题我们使用django的REST framework模块
不多说,pip安装djangorestframework后,配置setting文件,加入rest_framework应用
我们新建一个rest_searilizers文件,专门处理对象序列化
rest_searilizers.py内容如下
from rest_framework import serializers #导入序列化模块
from product.model import productModel
from project.models import projectModel
from ProductProject.models import ProductProjectModel
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = productModel# 序列化的模型
fields = '__all__'# fields 属性设置为特殊值 '__all__', 实例化时将可以看到所有字段
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = projectModel
fields = '__all__'
class ProductProjectSerializer(serializers.ModelSerializer):
project = ProjectSerializer(read_only=True)# 外键关联的对象并设置read_only=True
product = ProductSerializer(read_only=True)
class Meta:
model = ProductProjectModel
fields = '__all__'
是不是很简单,以上代码就将product和project与ProductProject通过外键id进行了关联
我们优化下SelectAll接口
# 查询所有
class SelectAll(View):
def post(self, request):
listRes = ProductProjectModel.objects.all()
listRes = rest_searilizers.ProductProjectSerializer(listRes, many=True) #注意这里,修改了
data_set = json.dumps(listRes.data, cls=DateEncoder)
data_set = json.loads(data_set)
return HttpResponse(json.dumps({"modelList": data_set, "code": 20000}, cls=DateEncoder),
content_type="application/json")
然后我们再调下ProductProject.SelectAll接口
可以看到结果已经是我想要的。
好了,现在前端又有个需求,我还想知道某个project的对应情况,即根据project的name进行查询。我们知道在ProductProject的表中,是没有name这个字段的,那怎么搞??
解决的办法有不少,比如我先根据name查出所有的project_id,再根据project_id查询对应关系等等
这里我们有个简单的方法,查出所有对象,然后根据外键的project对象数据进行筛选,代码如下
#根据条件查询
class SelectBySelective(View):
def post(self, request):
recordList = ProductProjectModel.objects.all()
dto = json.loads(request.body)
if dto.get('id'):
recordList = recordList.filter(id=dto.get('id'))
if dto.get('project_id'):
recordList = recordList.filter(project_id=dto.get('project_id'))
if dto.get('product_id'):
recordList = recordList.filter(product_id=dto.get('product_id'))
if dto.get('projectName'):
search = dto.get('projectName')
recordList = recordList.filter(project__name__icontains=search) #根据外键查出的project的name进行筛选
listRes = rest_searilizers.ProductProjectSerializer(recordList, many=True) #序列化查询结果
data_set = json.dumps(listRes.data)
data_set = json.loads(data_set)
return HttpResponse(json.dumps({"modelList": data_set, "code": 20000}),
content_type="application/json")
重点:
1、filter()方法,对数据进行筛选
2、project__name__icontains:对数据的project对象的name进行模糊查询
总结
在开发中,我们会经常遇到对象之间有关联的情况,都可以通过外键进行关联,然后在输出时对数据进行序列化,返回给前端。
演示代码:
https://github.com/danzi516/TestDev/tree/main/%E6%89%8B%E6%8A%8A%E6%89%8B/4/myproject
更多文章,关注一波,谢!