模型表:
from django.db import models
# Create your models here.
class StudentModel(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32,verbose_name='姓名')
age = models.SmallIntegerField(verbose_name='年龄')
class_mate_f = models.ForeignKey(to='ClassMateModel',on_delete=models.SET_NULL,null=True,
related_name='students',related_query_name='students',db_constraint=False)
class ClassMateModel(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64,verbose_name='班级名')
class ClassMateDetail(models.Model):
id = models.AutoField(primary_key=True)
address = models.CharField(max_length=32,verbose_name='地址')
class_mate_f = models.ForeignKey(to='ClassMateModel',on_delete=models.CASCADE,null=True,
related_name='detail',related_query_name='detail',db_constraint=False)
class TeacherModel(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32,verbose_name='姓名')
age = models.SmallIntegerField(verbose_name='年龄')
phone = models.CharField(max_length=13,verbose_name='手机号码')
class_mate_f = models.ManyToManyField(to='ClassMateModel',null=True,
related_name='teachers',related_query_name='teachers',db_constraint=False)
#通过其他三张表的related_name 后,ClassMateModel就多了三个虚拟字段:students,teachers,detail
一、外键在的一方
1、方式一:通过source来获取指定字段数据 【一对多和一对一的】
1.1、一对多 外键方
序列化器:
class StudentModelSerializer(serializers.ModelSerializer):
class_mate_pk = serializers.CharField(source='class_mate_f.id')
class_mate_name = serializers.CharField(source='class_mate_f.name')
class Meta:
model = models.StudentModel
fields = ['id','name','class_mate_pk','age','class_mate_name']
视图函数:
#学生创建
class StudentGenericAPIView(GenericAPIView):
authentication_classes = []
queryset = models.StudentModel.objects.all()
serializer_class = serializer.StudentModelSerializer
def get(self,request):
ser = self.get_serializer(instance = self.get_queryset(),many=True)
return Response({'code':200,'data':ser.data})
1.2、多对多 外键方 【不适应】
2、方式二:通过外键=序列化类() 【适用所有关系】
2.1、多对多:外键在这里
序列化器:
class ClassMateForTeacherModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.ClassMateModel
fields = ['id','name']
class TeacherModelSerializer(serializers.ModelSerializer):
class_mate_f = ClassMateForTeacherModelSerializer(many=True)
class Meta:
model = models.TeacherModel
fields = ['id','name','age','phone','class_mate_f']
视图类:
class TeacherGenericAPIView(GenericAPIView):
queryset = models.TeacherModel.objects.all()
serializer_class = serializer.TeacherModelSerializer
def get(self,request):
ser = self.get_serializer(instance = self.get_queryset(),many=True)
return Response({'code':200,'data':ser.data})
2.2、一对多,外键方 【学生表,嵌套班级】
序列化器:
class ClassMateForStudentModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.ClassMateModel
fields = ['id','name']
class StudentModelSerializer(serializers.ModelSerializer):
class_mate_f = ClassMateForStudentModelSerializer(read_only=True)
class Meta:
model = models.StudentModel
fields = ['id','name','class_mate_f','age']
视图:
class StudentGenericAPIView(GenericAPIView):
authentication_classes = []
queryset = models.StudentModel.objects.all()
serializer_class = serializer.StudentModelSerializer
def get(self,request):
ser = self.get_serializer(instance = self.get_queryset(),many=True)
return Response({'code':200,'data':ser.data})
3、方式三:通过depth 【适用所有关系】
起始表–外键-------------> 表1-外键--------------> 表2–外键------------->表3
这样,depth=4 ,会一直追踪外键,直达表中没有外键字段。
3.1、一对多:学生表- -外键----->班级表
#序列化器
class StudentModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.StudentModel
fields = ['id','name','class_mate_f','age']
depth = 2 #等于表数
#视图
class StudentGenericAPIView(GenericAPIView):
authentication_classes = []
queryset = models.StudentModel.objects.all()
serializer_class = serializer.StudentModelSerializer
def get(self,request):
ser = self.get_serializer(instance = self.get_queryset(),many=True)
return Response({'code':200,'data':ser.data})
3.2、多对多:老师-外键------->班级
#序列化器
class TeacherModelSerializer(serializers.ModelSerializer):
# class_mate_f = ClassMateForTeacherModelSerializer(many=True,read_only=True)
class Meta:
model = models.TeacherModel
fields = ['id','name','age','phone','class_mate_f']
depth =2 #涉及到的表数量
#视图
class TeacherGenericAPIView(GenericAPIView):
queryset = models.TeacherModel.objects.all()
serializer_class = serializer.TeacherModelSerializer
def get(self,request):
ser = self.get_serializer(instance = self.get_queryset(),many=True)
return Response({'code':200,'data':ser.data})
二、外键不在的一方[查询班级为例子]
【只能使用序列化器嵌套的方式】
注意:反向查询,都是通过反向查询字段=序列化器(many=True)
在这四张表中:ClassMateModel是没有一个外键字段,但是其他三张表都有ClassMateModel外键,
通过related_name, 在子查询时,就可以通过设置好的名字进行跨表,而且也查询结果是多个时也不需要使用_set了;
query_related_name 在联表查询时,通过设置好的名字进行跨表操作。
在查询班级信息时,需要班级详情信息、学生信息、老师信息;下面通过序列化器嵌套来实现
视图:
class ClassMateGenericAPIView(GenericAPIView):
authentication_classes = []
queryset = models.ClassMateModel.objects.all()
serializer_class = serializer.ClassMateModelSerializer
def get(self,request):
ser = self.get_serializer(instance = self.get_queryset(),many=True)
return Response({'code':200,'data':ser.data})
序列化器:
#老师
class TeacherForClassMateMdoelserializer(serializers.ModelSerializer):
class Meta:
model = models.TeacherModel
fields = ['id','name','phone']
#班级详情
class ClassDetailForClassMateModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.ClassMateDetail
fields =['address']
#学生
class StudentForClassMate(serializers.ModelSerializer):
class Meta:
model = models.StudentModel
fields = ['name','age']
#班级
class ClassMateModelSerializer(serializers.ModelSerializer):
teachers = TeacherForClassMateMdoelserializer(many=True,read_only=True)
detail = ClassDetailForClassMateModelSerializer(many=True,read_only=True)
students = StudentForClassMate(many=True,read_only=True)
class Meta:
model = models.ClassMateModel
fields =['id','name','teachers','students','detail']
extra_kwargs = {
'id':{'read_only':True},
'teachers':{'read_only':True},
'detail':{'read_only':True},
'students':{'read_only':True},
}
总结
1、通过related_name , ClassMateModel 相当于多了,students、teachers和detail 三个字段。
2、使用这三个字段来接收序列器对象,就可以实现序列化嵌套了。
3、注意,在实例化序列化器时,必须带上many=True 不然会报错。【因为外键不在当前模型类中,所有可能会有多个数据,即使是一对一的关系表,也要加many=true】
4、加上read_only=True ,不参与到反序列化中。如果该序列化器不参与反序列就无须写。
总结
1、通过related_name , ClassMateModel 相当于多了,students、teachers和detail 三个字段。
2、使用这三个字段来接收序列器对象,就可以实现序列化嵌套了。
3、注意,在实例化序列化器时,必须带上many=True 不然会报错。【因为外键不在当前模型类中,所有可能会有多个数据,即使是一对一的关系表,也要加many=true】
4、加上read_only=True ,不参与到反序列化中。如果该序列化器不参与反序列就无须写。