一、外键序列化字段PrimaryKeyRelatedField
首先说明下当前的两个model
类的关系:project
是interface
的主表,也就是一个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=[<UniqueValidator(queryset=Interfaces.objects.all())>])
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
<Interfaces: 项目1 - 接口1>
>>> serialzer = InterfacesSerializer(one)
>>> serialzer
InterfacesSerializer(<Interfaces: 项目1 - 接口1>):
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=[<UniqueValidator(queryset=Interfaces.objects.all())>])
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
续上面,如果想要默认输出的是project
的name
,那么就要用到StringRelatedFiled
字段。
StringRelatedFiled
:此字段将会被序列化为关联对象的字符串表达形式(__str__
方法)
- 1.首先重写
models.py
中的project
类,重写它的__str__
方法,让它返回name
:
def __str__(self):
return self.name
- 2.然后在
InterfaceModelSerializer
序列化类,用serializers.StringRelatedFiled
来定义projcet
这个外键字段,这样它就会去调用上一步骤中,project
模型类的__str__
方法,从而返回project
的name
值
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