这是对DRF官方文档:Serializer relations的翻译,根据个人的理解对内容做了些补充、修改和整理。

一,django模型间的关系

在我们对数据进行建模时,最重要的一点就是根据功能需求分析出实体及其关系,

在实现阶段:

  • 一个实体对应一个模型,一个模型就是一张数据表;
  • 实体间的关系由模型中的关系字段进行表示,模型间的关系就是数据表间的关系。

这种设计理念与关系型数据库的设计理念相符。而关系型数据库的强大之就处在于表示与处理各表之间的关联关系。为此,Django 提供了定义三种最常见的数据库关联关系的方法的关系字段:

  • OneToOneField:一对一关系
  • ForeignKey:多对一关系
  • ManyToManyField:多对多关系

二,检查序列化器实例详情

在使用 Serializer 类创建序列化器类时,对关系进行正确的的表示就非常重要。而使用 ModelSerializer 类创建序列化器类时,它会自动使用合适的字段处理模型间的关系,检查这些自动生成的字段对于如何确定自定义关系来说是非常有帮助的。

例如查看一个ModelSerializer 子类的实例详情:

>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print repr(serializer) # Or `print(repr(serializer))` in Python 3.x.
AccountSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all())

三,序列化关系字段

为了解释各种类型的关系字段,官网的教程为我们提供了一些简单的模型:用于音乐专辑以及其中的歌曲。

class Album(models.Model):
  album_name = models.CharField(max_length=100)
  artist = models.CharField(max_length=100) class Track(models.Model):
  album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE) # 多对一关系
  order = models.IntegerField()
  title = models.CharField(max_length=100)
  duration = models.IntegerField()   class Meta:
    unique_together = ('album', 'order')
    ordering = ['order']   def __str__(self):
    return '%d: %s' % (self.order, self.title)

模型中只用到多对一关系,Album 是主模型,产生主表,Track 是从模型,产生从表。

(一)StringRelatedField

字段作用:
主模型序列化器中的StringRelatedField字段可以使用从模型中的__str__方法来表示关联关系。

字段参数:

  • many:如果应用于多对一的关系,应该设置为 True。

使用示例:

class AlbumSerializer(serializers.ModelSerializer):
  tracks = serializers.StringRelatedField(many=True)   class Meta:
    model = Album
    fields = ['album_name', 'artist', 'tracks']

效果就是 tracks 属性将使用 Track 模型的 __str__ 方法来产生关联关系,并使用它返回的内容。

将产生以下形式的序列化结果:

{
  'album_name': 'Things We Lost In The Fire',
  'artist': 'Low',
  'tracks': [
  '1: Sunflower',
  '2: Whitetail',
  '3: Dinosaur Act',
  ...
  ]
}

(二)PrimaryKeyRelatedField

字段作用:
主模型序列化器中的PrimaryKeyRelatedField字段可以使用从模型中的主键字段来表示关联关系。

每个模型必须有一个主键。要么手动使用primary_key=True设置某字段为主键,否则 django 会为表创建名为 id (别名 pk)的自动增长的字段作为主键。

参考django doc:Automatic primary key fields
字段参数:

  • queryset:验证字段输入时用于模型实例查找的查询集。关系字段必须显式设置 queryset 或者 read_only=True。
  • many:如果应用于多对一的关系,应该设置为 True。
  • allow_null:是否允许该字段接受 None 或为空关系接受空字符串。默认值为 False。
  • pk_field:设置一个字段来控制主键值的序列化/反序列化。

使用示例:

class AlbumSerializer(serializers.ModelSerializer):
  tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)   class Meta:
    model = Album
    fields = ['album_name', 'artist', 'tracks']

默认PrimaryKeyRelatedField字段是可读写的。可以使用read_only标志来更改此行为。
效果就是 tracks 属性将使用 Track 模型的主键即 id (我们没在模型中指定主键)来产生关联关系,并使用主键值。

将产生以下形式的序列化结果:

{
  'album_name': 'Undun',
  'artist': 'The Roots',
  'tracks': [
  89,
  90,
  91,
  ...
  ]
}

(三)HyperlinkedRelatedField

字段作用:
主模型序列化器中的HyperlinkedRelatedField可以用来表示使用超链接的关系目标。从模型中的主键来表示关联关系。

该字段是为映射到一个URL的对象设计的,该URL接受一个 URL 关键字参数,使用lookup_field和lookup_url_kwarg参数设置。这适用于URL中包含一个主键或slug参数的URL。如果需要更复杂的超链接表示,则需要自定义字段,请参考自定义超链接字段。
字段参数:

  • view_name:应该用作关系目标的视图名称。如果使用标准的路由器类,则因该是一个格式为 modelname-detail 的字符串。是必要参数。
  • queryset:验证字段输入时用于模型实例查找的查询集。关系字段必须显式设置 queryset 或者 read_only=True。
  • many:如果应用于多对一的关系,应该设置为 True。
  • allow_null:是否允许该字段接受 None 或为空关系接受空字符串。默认值为 False。
  • lookup_field:应该用于查找的字段。应该对应于被引用视图上的 URL 关键字参数。默认设置是 pk。
  • lookup_url_kwarg:在 URL 配置文件中定义的关键字参数的名称,该参数是应该用于查找字段。默认使用与lookup_field相同的值。
  • format:如果使用格式后缀,超链接字段将为目标使用相同的格式后缀,除非使用format参数重写。

使用示例:

class AlbumSerializer(serializers.ModelSerializer):
  tracks = serializers.HyperlinkedRelatedField(
    many=True,
    read_only=True,
    view_name='track-detail'
    )   class Meta:
    model = Album
    fields = ['album_name', 'artist', 'tracks']

默认HyperlinkedRelatedField字段是可读写的。可以使用read_only标志来更改此行为。
效果就是 tracks 属性将使用 Track 模型的主键即 id (我们没在模型中指定主键)来产生关联关系,并使用主键值。

将产生以下形式的序列化结果:

{
  'album_name': 'Graceland',
  'artist': 'Paul Simon',
  'tracks': [
  'http://www.example.com/api/tracks/45/',
  'http://www.example.com/api/tracks/46/',
  'http://www.example.com/api/tracks/47/',
  ...
  ]
}

(四)SlugRelatedField

字段作用:
主模型序列化器中的SlugRelatedField字段可以使用从模型中的Slug字段来表示关联关系。可以使用目标上的字段来表示关系的目标。

django向模型提供Slug字段来创建更加完善的 URL。Rest Framework的SlugRelatedField字段也采用相同的理念。
django相关字段解释(slug)、在 Django 中生成 slug、django中slug是什么?有什么用?可以应用于什么地方?

字段参数:

  • slug_field:从模型中用来表示它的字段。这应该是唯一标识任何给定实例的字段。是必要参数。当使用
  • queryset:验证字段输入时用于模型实例查找的查询集。关系字段必须显式设置 queryset 或者 read_only=True。
  • many:如果应用于多对一的关系,应该设置为 True。
  • allow_null:是否允许该字段接受 None 或为空关系接受空字符串。默认值为 False。

使用示例:

class AlbumSerializer(serializers.ModelSerializer):
  tracks = serializers.SlugRelatedField(
    many=True,
    read_only=True,
    slug_field='title'
    )   class Meta:
    model = Album
    fields = ['album_name', 'artist', 'tracks']

默认情况下,这个字段是可读写的。可以使用read_only标志来更改此行为。还必须确保模型中该字段设置了unique=True。
效果就是 tracks 属性将使用 Track 模型的 title 字段来产生关联关系,并使用其值。

将产生以下形式的序列化结果:

{
  'album_name': 'Dear John',
  'artist': 'Loney Dear',
  'tracks': [
  'Airport Surroundings',
  'Everything Turns to You',
  'I Was Only Going Out',
  ...
  ]
}

(五)HyperlinkedIdentityField

字段作用:
主模型序列化器中的HyperlinkedIdentityField字段可以作为身份关系应用,例如HyperlinkedModelSerializer上的“url”字段。它也可以用于对象的属性。

字段参数:

  • view_name:应该用作关系目标的视图名称。如果使用标准的路由器类,则因该是一个格式为 modelname-detail 的字符串。是必要参数。
  • lookup_field:应该用于查找的字段。应该对应于被引用视图上的 URL 关键字参数。默认设置是 pk。
  • lookup_url_kwarg:在 URL 配置文件中定义的关键字参数的名称,该参数是应该用于查找字段。默认使用与lookup_field相同的值。
  • format:如果使用格式后缀,超链接字段将为目标使用相同的格式后缀,除非使用format参数重写。

使用示例:

class AlbumSerializer(serializers.HyperlinkedModelSerializer):
  track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')   class Meta:
    model = Album
    fields = ['album_name', 'artist', 'track_listing']

这个字段是只读写的。
效果就是 tracks 属性将使用 Track 模型的主键即 id (我们没在模型中指定主键)来产生关联关系,并使用主键值。

将产生以下形式的序列化结果:

{
  'album_name': 'The Eraser',
  'artist': 'Thom Yorke',
  'track_listing': 'http://www.example.com/api/track_list/12/',
}

四,嵌套关系

与在序列化器中使用序列化关系字段专门序列化模型间关系的方式所不同的是,序列化器本身还能作为序列化字段来表示一种模型间的嵌套关系。例如:

class TrackSerializer(serializers.ModelSerializer):
  class Meta:
    model = Track
    fields = ['order', 'title', 'duration'] class AlbumSerializer(serializers.ModelSerializer):
  tracks = TrackSerializer(many=True, read_only=True)   class Meta:
    model = Album
    fields = ['album_name', 'artist', 'tracks']

  

序列化效果:

>>> album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse')
>>> Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)
<Track: Track object>
>>> Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264)
<Track: Track object>
>>> Track.objects.create(album=album, order=3, title='Encore', duration=159)
<Track: Track object>
>>> serializer = AlbumSerializer(instance=album)
>>> serializer.data
{
  'album_name': 'The Grey Album',
  'artist': 'Danger Mouse',
  'tracks': [
  {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
  {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
  {'order': 3, 'title': 'Encore', 'duration': 159},
  ...
  ],
}

默认情况下,嵌套序列化器是只读的。如果要支持对嵌套序列化器字段的写操作,则需要实现 create() 和/或 update() 方法,以显式地指定应如何保存包括嵌套内容在内的所有数据:

class TrackSerializer(serializers.ModelSerializer):
  class Meta:
    model = Track
    fields = ('order', 'title', 'duration') class AlbumSerializer(serializers.ModelSerializer):
  tracks = TrackSerializer(many=True)   class Meta:
    model = Album
    fields = ('album_name', 'artist', 'tracks')   def create(self, validated_data):
    tracks_data = validated_data.pop('tracks')
    album = Album.objects.create(**validated_data)
    for track_data in tracks_data:
      Track.objects.create(album=album, **track_data)
    return album >>> data = {
  'album_name': 'The Grey Album',
  'artist': 'Danger Mouse',
  'tracks': [
    {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
    {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
    {'order': 3, 'title': 'Encore', 'duration': 159},
    ],
}
>>> serializer = AlbumSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
<Album: Album object>

五,自定义关系字段

如果希望实现在现有的关系样式都不适合的输出需求时,则可以自定义关系字段:子类化RelatedField,并实现.to_representation(self, value)方法:

此方法需要value参数(通常是一个模型实例),并应该返回所需要的序列化表示形式。

import time

class TrackListingField(serializers.RelatedField):
  def to_representation(self, value):
    duration = time.strftime('%M:%S', time.gmtime(value.duration))
  return 'Track %d: %s (%s)' % (value.order, value.name, duration) class AlbumSerializer(serializers.ModelSerializer):
  tracks = TrackListingField(many=True)   class Meta:
    model = Album
    fields = ['album_name', 'artist', 'tracks']

效果如下:

{
  'album_name': 'Sometimes I Wish We Were an Eagle',
  'artist': 'Bill Callahan',
  'tracks': [
  'Track 1: Jim Cain (04:39)',
  'Track 2: Eid Ma Clack Shaw (04:19)',
  'Track 3: The Wind and the Dove (04:34)',
  ...
  ]
}

如果希望实现可读写的关系字段,则必须实现.to_internal_value(self, data)方法。

如果希望提供基于上下文的动态queryset,则需要重写.get_queryset(self),而不是在类上或初始化字段时指定.queryset。

六,自定义超链接字段

如果希望自定义超链接字段的行为,以表示需要多个查询字段的 URL,则可以通过子类化 HyperlinkedRelatedField 来实现。有两个方法重需要写:

  • 1, get_url(self, obj, view_name, request, format):用于将对象实例映射到其 URL 表示。

如果 view_name 和 lookup_field 属性未配置为正确匹配 URL,可能会引发 NoReverseMatch。

  • 2,get_object(self, queryset, view_name, view_args, view_kwargs):用于支持可写的超链接字段,以便将传入的 URL 映射回它们表示的对象。对于只读的超链接字段,无需重写此方法。

此方法的返回值应该是与匹配的 URL 参数对应的对象,可能会引发 ObjectDoesNotExist 异常
假设我们有一个 customer 对象的 URL,它接受两个关键字参数:

/api/<organization_slug>/customers/<customer_pk>/

这时不能用仅接受单个查找字段的默认实现来表示,就需要重写 HyperlinkedRelatedField 以获得我们想要的行为:

from rest_framework import serializers
from rest_framework.reverse import reverse class CustomerHyperlink(serializers.HyperlinkedRelatedField):
  # 我们将它们定义为类属性,因此我们不需要将它们作为参数传递。
  view_name = 'customer-detail'
  queryset = Customer.objects.all()   def get_url(self, obj, view_name, request, format):
    url_kwargs = {
      'organization_slug': obj.organization.slug,
      'customer_pk': obj.pk
      }
  return reverse(view_name, kwargs=url_kwargs, request=request, format=format)   def get_object(self, view_name, view_args, view_kwargs):
    lookup_kwargs = {
      'organization__slug': view_kwargs['organization_slug'],
      'pk': view_kwargs['customer_pk']
      }
  return self.get_queryset().get(**lookup_kwargs)

请注意,如果想将此样式与通用视图一起使用,那么还需要在视图上重写 .get_object 以获得正确的查找行为。

官方建议还是尽可能使用序列化关系字段 API ​​,但适度使用嵌套的 URL 样式也是合理的。

文章知识点与官方知识档案匹配,可进一步学习相关知识
————————————————
版权声明:本文为CSDN博主「dangfulin」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dangfulin/article/details/122799426

Django Rest Framework中文文档:Serializer relations的更多相关文章

  1. Django REST framework 中文文档

    Django REST framework介绍 现在前后端分离的架构设计越来越流行,业界甚至出现了API优先的趋势. 显然API开发已经成为后端程序员的必备技能了,那作为Python程序员特别是把Dj ...

  2. Django 1.10中文文档—第一个Django应用Part1

    在本教程中,我们将引导您完成一个投票应用程序的创建,它包含下面两部分: 一个可以进行投票和查看结果的公开站点: 一个可以进行增删改查的后台admin管理界面: 我们假设你已经安装了Django.您可以 ...

  3. Django 1.10中文文档-第一个应用Part2-模型和管理站点

    本教程继续Part1.我们将设置数据库,创建您的第一个模型,并快速介绍Django的自动生成的管理网站. 数据库设置 现在,编辑mysite/settings.py.它是一个用模块级别变量表示Djan ...

  4. Django 1.10中文文档-执行查询

    Django 1.10中文文档: https://github.com/jhao104/django-chinese-doc 只要创建好 数据模型, Django 会自动为生成一套数据库抽象的API, ...

  5. Django 1.10中文文档-聚合

    Django 数据库抽象API 描述了使用Django 查询来增删查改单个对象的方法. 然而,有时候你要获取的值需要根据一组对象聚合后才能得到. 这个主题指南描述了如何使用Django的查询来生成和返 ...

  6. Django 1.10中文文档-第一个应用Part7-自定义管理站点

    开发第一个Django应用,Part7 本教程上接Part6.将继续完成这个投票应用,本节将着重讲解如果用Django自动生成后台管理网站. 自定义管理表单 通过admin.site.register ...

  7. Django 1.10中文文档-第一个应用Part6-静态文件

    本教程上接Part5 .前面已经建立一个网页投票应用并且测试通过,现在主要讲述如何添加样式表和图片. 除由服务器生成的HTML文件外,网页应用一般还需要提供其它必要的文件——比如图片.JavaScri ...

  8. Django 1.10中文文档-第一个应用Part5-测试

    本教程上接教程Part4. 前面已经建立一个网页投票应用,现在将为它创建一些自动化测试. 自动化测试简介 什么是自动化测试 测试是检查你的代码是否正常运行的行为.测试也分为不同的级别.有些测试可能是用 ...

  9. Django 1.10中文文档-第一个应用Part4-表单和通用视图

    本教程接Part3开始.继续网页投票应用程序,并将重点介绍简单的表单处理和精简代码. 一个简单表单 更新一下在上一个教程中编写的投票详细页面的模板polls/detail.html,让它包含一个HTM ...

  10. Django 1.10中文文档-第一个应用Part3-视图和模板

    本教程上接Django 1.10中文文档-第一个应用Part2-模型和管理站点.我们将继续开发网页投票这个应用,主要讲如何创建一个对用户开放的界面. 概览 视图是Django应用中的一“类”网页,它通 ...

随机推荐

  1. 字符编码,存储引擎及MySQL字段类型相关知识点

    字符编码,存储引擎及MySQL字段类型相关知识点 一.字符编码 1.在终端输入\s,查看数据库的基本信息(当前用户,版本,编码,端口号) 2.默认的配置文件是my-default.ini 拷贝上述的文 ...

  2. 真正“搞”懂HTTP协议11之代理服务

    代理,其实全称应该叫做代理服务器,它是客户端与服务器之间得中间层,本质上来说代理就是一个服务器,在HTTP的链路中插入的一个中间环节,就是代理服务器啦.所谓的代理服务就是指:服务本身不生产内容,而是处 ...

  3. spring in action day-06 JMS -ActiveMQ Artemi

    JMS -ActiveMQ Artemi JMS:它是一个规范,类似于jdbctemplate Spring提供了jmstemplate来发送和接收消息. 搭建JMS环境 1.引入依赖 我们要使用的消 ...

  4. JAVA虚拟机02---JAVA虚拟机运行时数据区域简介

      JAVA虚拟机运行时数据区域 1.程序计数器 1)它可以看做是当前线程执行的字节代码的行指示器,通过改变计数器的值来决定下一步执行的代码 2)它是线程私有的,每个线程都有自己的程序计数器(JAVA ...

  5. 亲测有效! Super PhotoCut Pro 超级抠图工具 V2.8.8 for mac 破解版

    亲测有效! Super PhotoCut Pro 超级抠图工具 V2.8.8 for mac  破解版 Super PhotoCut 是一款专业的,非常易于使用的图片抠图工具.它能够准确地覆盖你想要去 ...

  6. NuGet私有服务器ProGet Docker搭建和公司中实战用法

    一.什么时候需要用到NuGet私有服务器 很多公司中架构师会搭建一个统一的项目基础架构模板,然后全部新项目都会拿这个基础架构来开发新的项目,那架构中就会有很多的中间件,比喻公司内部的封装好的Redis ...

  7. 自动化测试如此容易!多语言自动化测试框架 Selenium 编程(C#篇)

    介绍 Selenium 官网:https://www.selenium.dev/ Selenium 是功能强大的自动化测试工具集,是支持 Web 浏览器自动化的一系列工具和库的总括项目,一共包括以下三 ...

  8. 重要内置函数、常见内置函数(了解)、可迭代对象、迭代器对象、for循环原理、异常捕获

    目录 一.重要内置函数 二.常见内置函数(了解) 三.可迭代对象 四.迭代器对象 五.for循环内部原理 六.捕捉异常 一.重要内置函数 1. zip 说白了就是压缩几组数据值,说细了就是将可迭代对象 ...

  9. asp汉字转拼音小写

    <%'//获取汉字的首字母 ,ANSII编码function getpychar(char) dim tmpp:tmpp=65536+asc(char) if(tmpp>=45217 an ...

  10. 百度脑图kityminder

    KityMinder Editor 是一款强大.简洁.体验优秀的脑图编辑工具,适合用于编辑树/图/网等结构的数据. 编辑器由百度 FEX 基于 kityminder-core 搭建,并且在百度脑图中使 ...