定义序列化器之关联属性(一对多、多对多)

定义序列化器,通常是拿模型类的代码过来修改一下。但是如果遇到有关联属性的时候,应该怎么写呢?

假设有两个模型类,一个是员工,一个是部门。部门与员工是一对多关系。那么在定义序列器的时候怎么写关联属性的语句呢?

先把没有涉及关联属性的字段写成序列化器:

from rest_framework import serializers


class DepartmentSerializer(serializers.Serializer):
    """部门序列化器类"""
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=20)
    create_date = serializers.DateField()class EmployeeSerializer(serializers.Serializer):
    """员工序列化器"""

    choices_gender = (
        (0, ''),
        (1, ''),
    )

    name = serializers.CharField(max_length=20)
    age = serializers.IntegerField()
    gender = serializers.ChoiceField(default=0, choices=choices_gender)
    salary = serializers.DecimalField(max_digits=8, decimal_places=2)
    comment = serializers.CharField(max_length=300)
    hire_date = serializers.DateField()
  • 一对多关系中,多的那方的序列化器关联属性的写法:

如果我要对员工对象序列化时有这样的效果:

# 第一种效果
{ "name": "赵小一",
    ..., "department": 1, # 第1种:PrimaryKeyRelatedField }

# 第二种效果 { "name": "赵小一",
    ..., "department": "研发部", # 第2种:StringRelatedField }

# 第三种效果 { "name": "赵小一",
    ..., "department": { # 第3种:DepartmentSerializer "id": 1, "name": "研发部", "create_date": "2018-1-1" } }

员工序列化器的定义如下:

class EmployeeSerializer(serializers.Serializer):
    """员工序列化器"""

    choices_gender = (
        (0, ''),
        (1, ''),
    )

    name = serializers.CharField(max_length=20)
    age = serializers.IntegerField()
    gender = serializers.ChoiceField(default=0, choices=choices_gender)
    salary = serializers.DecimalField(max_digits=8, decimal_places=2)
    comment = serializers.CharField(max_length=300)
    hire_date = serializers.DateField()
    # 定义序列化器时关联属性的设置
    # 1.1 返回关联属性的主键,设置属性为read_only=True表示修改时,即使传过来的员工信息有部门的id,也不做修改,保留原始的值!
    department = serializers.PrimaryKeyRelatedField(read_only=True)
    # 1.2 返回关联属性的主键,设置属性为查询集,表示修改时,当你要修改部门时,如果查询集有,可以修改,如果没有,不可以修改!
    department = serializers.PrimaryKeyRelatedField(queryset=Department.objects.all())
    # 2 返回关联属性的类的__str__方法的值。如果我们想要返回部门的名称,可以在model里面增加__str__方法返回部门名称
    department = serializers.StringRelatedField()
    # 3 返回关联属性的所有属性值时,可以这样写:
    department = DepartmentSerializer()
  • 一对多关系中,一的那方的序列化器关联属性的写法:(多对多关系的两边都可以这样写

部门序列化器的定义如下:

class DepartmentSerializer(serializers.Serializer):
    """部门序列化器类"""
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=20)
    create_date = serializers.DateField()
    is_delete = serializers.BooleanField(default=False)
    # 返回关联属性的主键,因为有多个,所以必须加上many=True
    employee_set = serializers.PrimaryKeyRelatedField(read_only=True,many=True)
    # 返回关联属性的类的__str__方法的值。如果我们想要返回员工的名字,可以在model里面增加__str__方法返回员工的名字。
    employee_set = serializers.StringRelatedField(many=True)
    # 返回关联属性的所有属性值
    employee_set = EmpSerializer(many=True)

注意:因为一的这方序列化时会出现多条关联属性,所以必须加上many=True。

 

  • 一个小小的坑

如果在一个文件中,定义了员工和部门的序列化器,并且,两个序列化器都返回关联属性的所有属性值时:

部门序列化器有这句语句:

employee = EmployeeSerializer(many = True)

员工序列化器有这句语句:

department = DepartmentSerializer()

此时会出现相互引用的情况,导致出错!

解决办法:

在部门序列化器前再加多一个员工序列化器,并且把department = DepartmentSerializer()删掉!

原文地址:https://www.cnblogs.com/chichung/p/9937176.html