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=[<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

续上面,如果想要默认输出的是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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容