Django模型关系建表查询和序列化嵌套使用
模型部分
1.一对一
模型:
class Class(models.Model): id = models.AutoField(primary_key=True) cname = models.CharField(max_length=32) cdata = models.DateField() def __str__(self): return self.cname class Student(models.Model): id = models.AutoField(primary_key=True) sname = models.CharField(max_length=32) # 一对多 # cid = models.ForeignKey(to="Class",to_field="id",related_name="student") cid = models.ForeignKey(Class, to_field="id",related_name='class_related') # 一对一 detail = models.OneToOneField(StudentDetail, to_field="id",related_name='detail_related') # 等同于如下的代码 # detail = models.ForeignKey(to="StudentDetail",to_field="id",unique=True) class StudentDetail(models.Model): id = models.AutoField(primary_key=True) height = models.PositiveIntegerField() email = models.EmailField() memo = models.CharField(max_length=128)
查询:
#正向查询(由学生信息表查询学生详情表) stu = models.Student.objects.first() stu.detail.email '234@qq' #反向查询(由学生详情表反向查询学生信息表) std = StudentDetail.objects.first() std.detailtostudent_related '小明'
2.一对多
模型:
class Class(models.Model): id = models.AutoField(primary_key=True) cname = models.CharField(max_length=32) cdata = models.DateField() def __str__(self): return self.cname class Student(models.Model): id = models.AutoField(primary_key=True) sname = models.CharField(max_length=32) # 一对多 cid = models.ForeignKey(Class, to_field="id",related_name='class_related') # 一对一 detail = models.OneToOneField(StudentDetail, to_field="id",related_name='detail_related')
查询:
#正向查询 stu = Student.objects.first() <Student: 小明> stu.cid <Class: 火箭1班> #反向查询 cls = Class.objects.first() cls.class_related.all() <QuerySet [<Student: 小明>, <Student: 小花>, <Student: 小王>]>
3.多对多
模型:
class Class(models.Model): id = models.AutoField(primary_key=True) cname = models.CharField(max_length=32) cdata = models.DateField() def __str__(self): return self.cname class Teacher(models.Model): id = models.AutoField(primary_key=True) tname = models.CharField(max_length=32) classes = models.ManyToManyField(Class,related_name='mclass_related') def __str__(self): return self.tname
查询:
#正向查询: from relation.models import Class,Teacher tea = Teacher.objects.first() tea.classes.all() <QuerySet [<Class: 一班>, <Class: 二班>, <Class: 三班>, <Class: 四班>]> #反向查询: cls = Class.objects.first() cls.mclass_related.all() <QuerySet [<Teacher: 王老师>, <Teacher: 赵老师>, <Teacher: 李老师>, <Teacher: 冯老师>]>
模型关系总结:django orm依赖外键来建立模型与模型之间的关系,related_name可选参数提供了反查询的途径,同样不适用related_name,使用【小写模型名字_set】一样可以做到,怎么方便怎么来,制定related_name在后面的序列化嵌套使用中会极大的简化我们序列化嵌套的操作难度。
序列化器部分
1.一对一:
序列化器:
class StudentSerializer(serializers.ModelSerializer): detail = StudentDetailSerializer() #student序列化器,提供student和studentdetail的序列化嵌套,返回学生基本信息和详细信息 class Meta: model = Student fields = ('sname', 'detail') def validate(self, attrs): return attrs def create(self, validated_data): #创建数据,我是先分解开数据,然后按照外键关系进行模型操作,创建mysql数据 cid = Class.objects.create(**validated_data['cid']) detail = StudentDetail.objects.create(**validated_data['detail']) user = Student.objects.create(sname=validated_data['sname'], cid=cid, detail=detail) user.save() return user
视图:
class StudentView(GenericAPIView): serializer_class = StudentSerializer queryset = Student.objects.all() # renderer_classes = (Utf8JSONRenderer,) def get(self, request): data = self.get_queryset() serializer = self.get_serializer(data, many=True) return Response(serializer.data) def post(self, request): data = request.data serializer = self.get_serializer(data=data) serializer.is_valid() serializer.save() return Response(serializer.data)
效果:
{ "sname": "小王", "detail": { "height": 180, "email": "123@qq.com", "memo": "lol" } }
2.一对多
序列化器:
class BjSerializer(serializers.ModelSerializer): #班级序列化器 class Meta: model = Class fields = ('cname', 'cdata') class StudentDetailSerializer(serializers.ModelSerializer): #学生详细信息序列化器 class Meta: model = StudentDetail fields = ('height', 'email', 'memo') class StudentSerializer(serializers.ModelSerializer): #嵌套学生详细信息和班级序列化器的学生序列化器 cid = BjSerializer() detail = StudentDetailSerializer() class Meta: model = Student fields = ('sname', 'cid', 'detail') def validate(self, attrs): return attrs def create(self, validated_data): cid = Class.objects.create(**validated_data['cid']) detail = StudentDetail.objects.create(**validated_data['detail']) user = Student.objects.create(sname=validated_data['sname'], cid=cid, detail=detail) user.save() return user
视图:
class StudentView(GenericAPIView): serializer_class = StudentSerializer queryset = Student.objects.all() # renderer_classes = (Utf8JSONRenderer,) def get(self, request): data = self.get_queryset() serializer = self.get_serializer(data, many=True) return Response(serializer.data) def post(self, request): data = request.data serializer = self.get_serializer(data=data) serializer.is_valid() serializer.save() return Response(serializer.data)
效果:
{ "sname": "小王", "cid": { "cname": "一班", "cdata": "2018-11-17" }, "detail": { "height": 180, "email": "123@qq.com", "memo": "lol" } },
3.多对多对
效果(查询出当前老师的所有班级和对应的班级的所有学生):
{ "tname": "王老师", "classes": [ { "cname": "一班", "class_related": [ { "sname": "小王", "detail": { "height": 180, "email": "123@qq.com", "memo": "lol" } } ] }, { "cname": "二班", "class_related": [ { "sname": "小刘", "detail": { "height": 175, "email": "234@qq.com", "memo": "dnf" } } ] }, { "cname": "三班", "class_related": [ { "sname": "小李", "detail": { "height": 170, "email": "345@qq.com", "memo": "wow" } } ] }, { "cname": "四班", "class_related": [ { "sname": "小赵", "detail": { "height": 165, "email": "456@qq.com", "memo": "h1z1" } } ] } ] },
序列化器:
class StudentsSerializer(serializers.ModelSerializer): detail = StudentDetailSerializer() class Meta: model = Student fields = ('sname','detail') class ClassSerializer(serializers.ModelSerializer): #此处可以使用related_name来关联上student表 class_related = StudentsSerializer(many=True) class Meta: model = Class fields = ('cname','class_related') class TeacherSerializer(serializers.ModelSerializer): classes = ClassSerializer(many=True) class Meta: model = Teacher fields = ('tname','classes')
视图:
class TeacherView(GenericAPIView): serializer_class = TeacherSerializer queryset = Teacher.objects.all() # renderer_classes = (Utf8JSONRenderer,) def get(self, request): data = self.get_queryset() serializer = self.get_serializer(data, many=True) return Response(serializer.data)