15、Django_rest framework_序列化器之自定义外键

一、外键序列化字段PrimaryKeyRelatedField

首先说明下当前的两个model类的关系:projectinterface的主表,也就是一个project有多个interface
在对子表进行序列化时,会默认产生一个关联主表模型类的外键字段PrimaryKeyRelatedField

  • 首先对interface模型创建序列化器
from rest_framework import serializers
from interfaces.models import Interfaces

class InterfaceModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Interfaces
        fields = '__all__'
  • 从下面查看序列化的结果可以看出,序列化器会使数据库模型中的外键字段,默认产生PrimaryKeyRelatedField外键序列化字段
>>> from interfaces.serializer import InterfacesSerializer
>>> InterfacesSerializer()
# 下面是结果
InterfacesSerializer():
    id = IntegerField(help_text='id主键', label='Id主键', read_only=True)
    create_time = DateTimeField(help_text='创建时间', label='创建时间', read_only=True)
    update_time = DateTimeField(help_text='更新时间', label='更新时间', read_only=True)
    name = CharField(help_text='接口名称', label='接口名称', max_length=100, validators=[])
    tester = CharField(help_text='测试人员', label='测试人员', max_length=100)
    desc = CharField(allow_blank=True, allow_null=True, help_text='接口描述', label='接口描述', max_length=500, required=False)
    project = PrimaryKeyRelatedField(help_text='所属项目', queryset=Projects.objects.all())
  • 并且,该外键序列化字段输出的值,默认是对应的记录的外键ID值(比如这里查询id=1的interface的信息,project外键输出的就是该interface对应的project信息的ID值)
>>> from interfaces.models import Interfaces
>>> one = Interfaces.objects.get(id=1)
>>> one

>>> serialzer = InterfacesSerializer(one)
>>> serialzer
InterfacesSerializer():
    id = IntegerField(help_text='id主键', label='Id主键', read_only=True)
    create_time = DateTimeField(help_text='创建时间', label='创建时间', read_only=True)
    update_time = DateTimeField(help_text='更新时间', label='更新时间', read_only=True)
    name = CharField(help_text='接口名称', label='接口名称', max_length=100, validators=[])
    tester = CharField(help_text='测试人员', label='测试人员', max_length=100)
    desc = CharField(allow_blank=True, allow_null=True, help_text='接口描述', label='接口描述', max_length=500, required=False)
    project = PrimaryKeyRelatedField(help_text='所属项目', queryset=Projects.objects.all())
>>> serialzer.data
# 结果
{'id': 1, 'create_time': '2020-07-15T18:31:00+08:00', 'update_time': '2020-07-15T18:32:01.070581+08:00', 'name': '项目1 - 接口1', 'tester': 'test1', 'desc': '这是项目1 - 接口1', 'project': 1}

二、外键字段序列化为关联模型对象的__str__方法:StringRelatedField

续上面,如果想要默认输出的是projectname,那么就要用到StringRelatedFiled字段。
StringRelatedFiled:此字段将会被序列化为关联对象的字符串表达形式(__str__方法)

  • 1.首先重写models.py中的project类,重写它的__str__方法,让它返回name
def __str__(self):
    return self.name
  • 2.然后在InterfaceModelSerializer序列化类,用serializers.StringRelatedFiled来定义projcet这个外键字段,这样它就会去调用上一步骤中,project模型类的__str__方法,从而返回projectname
class InterfaceModelSerializer(serializers.ModelSerializer):
    # StringRelatedFiled,此字段将会被序列化为关联对象的字符串表达形式(__str__方法)
    project = serializers.StringRelatedFiled(label='所属项目名称',read_only=True)
    class Meta:
        model = Interfaces
        fields = '__all__'
  • 结果:
>>> from interfaces.serializer import InterfacesSerializer
>>> from interfaces.models import Interfaces
>>> one = Interfaces.objects.get(id=1)
>>> serialzer = InterfacesSerializer(one)
>>> serialzer.data
{'id': 1, 'project': '项目一', 'create_time': '2020-07-15T18:31:00+08:00', 'update_time': '2020-07-15T18:32:01.070581+08:00', 'name': '项目1 - 接口1', 'tester': 'test1', 'desc': '这是项目1 - 接口1'}
三、外键字段序列化为关联模型对象的指定字段:SlugRelatedField

此时想要得到关联project的描述desc字段的值,那么就使用serializers.SlugRelatedField
serializers.SlugRelatedField:此字段将会被序列化为关联对象的指定字段的值

  • InterfaceModelSerializer序列化类,用serializers.SlugRelatedField来定义projcet这个外键字段,这样它就会返回project的指定字段值
  • 注意:如果指定的外键字段,只需序列化输出,则需指定参数read_only=True;如果也需要反序列化输入,那么需传递一个queryset来进行校验所传入的值:queryset=xxx
class InterfaceModelSerializer(serializers.ModelSerializer):
    # SlugRelatedField,此字段将会被序列化为关联对象的指定字段的值
    project = serializers.StringRelatedFiled(slug_field='leader',read_only=True)

    class Meta:
        model = Interfaces
        fields = '__all__'
  • 结果:
>>> from interfaces.serializer import InterfacesSerializer
>>> from interfaces.models import Interfaces
>>> one = Interfaces.objects.get(id=1)
>>> serialzer = InterfacesSerializer(one)
>>> serialzer.data
# 结果,第二个字段
{'id': 1, 'project': 'leader1', 'create_time': '2020-07-15T18:31:00+08:00', 'update_time': '2020-07-15T18:32:01.070581+08:00', 'name': '项目1 - 接口1', 'tester': 'test1', 'desc': '这是项目1 - 接口1'}

四、外键字段序列化为关联模型对象的序列化器

想要通过外键字段,得到关联模型对象的序列化器

  • 首先在在InterfaceModelSerializer序列化类的py文件,导入project的序列化类,然后再用这个序列化类定义project字段:
from projects.serializer import ProjectSerializer
project = ProjectSerializer(label='所属项目', read_only=True)
  • 结果:
one_interface = Interfaces.objects.get(id=1)
print(one_interface )
### 下面是结果
>>> from interfaces.serializer import InterfacesSerializer
>>> from interfaces.models import Interfaces
>>> one = Interfaces.objects.get(id=1)
>>> serialzer = InterfacesSerializer(one)
>>> serialzer.data
{'id': 1, 'project': OrderedDict([('id', 1), ('create_time', '2020-07-15T18:28:00+08:00'), ('update_time', '2020-07-15T18:29:38.245015+08:00'), ('name', '项目一'), ('tester', 'test1'), ('leader', 'leader1'), ('programmer', 'programmer1'), ('publish_app', 'app1'), ('desc', '第一个项目')]), 'create_time': '2020-07-15T18:31:00+08:00', 'update_time': '2020-07-15T18:32:01.070581+08:00', 'name': '项目1 - 接口1', 'tester': 'test1', 'desc': '这是项目1 - 接口1'}
五、反向指定序列化字段[子表模型类名小写_set]

从上面可以知道,在对子表进行序列化时,会默认产生一个关联主表模型类的外键字段PrimaryKeyRelatedField
但是如果对主表进行序列化的时候,并不会默认产生关联子表模型类的字段(比如查询一个id=1的project的信息,并不会默认查询该project的interface的信息)
此时,我们可以手动指定添加这个关联字段。
比如,我想要在查询一个project的同时,得到该projcet的所有interface信息

  • project类的序列化器中添加(变量名需要是子表模型类名小写_set,因为要得到其关联所有的interface信息,所以需要传参many=True)
## 变量名需要是子表模型类名小写_set,并且传参many=True
interfeces_set = serializers.StringRelatedField(many=True)
  • 然后进行序列化并查看
from projects.serializer import ProjectModelSerializer from projects.models import Projects
p = Projects.objects.get(id=1)
ProjectModelSerializer(p).data
  • 结果(该projecet只有一个interface)
{'id': 1, 'name': '项目一', 'interfaces_set': ['Interfaces object (1)', 'Interfaces object (2)'], 'programer': 'lzl',  'desc': '我是项目一的描述'}
  • 如果在字表model中,定义了related_name这个字段,那么反向指定序列化字段的值也改变。
    比如说,修改interfaces/models.py
class Interfaces(BaseModel):
    ...
    # related_name='interfaces',则反向指定序列化字段的值也为interfaces
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE, related_name='interfaces', help_text='所属项目') 
  ...

那么,上面例子的interfeces_set应该改成interfaces

你可能感兴趣的:(15、Django_rest framework_序列化器之自定义外键)