rest framework serializer
串行器
扩大串行的用处是什么,我们想地址。然而,这不是一个简单的问题,它会采取一些严重的设计工作。
-罗素基思-马吉,Django的用户组
串行器允许诸如查询集和模型实例复杂的数据转换为原生的Python数据类型,然后可以很容易地呈现为JSON
,XML
或其他内容类型。串行器还提供反序列化,允许解析的数据被转换回复杂类型,第一验证传入的数据之后。
在REST架构工作的串行非常类似于Django的Form
和ModelForm
类。我们提供了一个Serializer
类,它让你能够控制你的反应的输出强大的,通用的方式,以及一个ModelSerializer
提供有用的快捷方式创建序列化类处理模型实例和查询集。
声明串行器
首先让我们来创建一个简单的对象,我们可以使用例如用途:
from datetime import datetime
class Comment(object):
def __init__(self, email, content, created=None):
self.email = email
self.content = content
self.created = created or datetime.now()
comment = Comment(email='leila@example.com', content='foo bar')
我们要声明一个序列化,我们可以使用序列化和反序列化数据相对应Comment
的对象。
声明串行看起来非常相似,声明形式:
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
序列化对象
我们现在可以使用CommentSerializer
序列化评论,或者评论列表。再次,使用Serializer
类看起来很像使用Form
类。
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
在这一点上,我们已经翻译模型实例成Python原生类型。要完成序列化过程中,我们呈现数据到json
。
from rest_framework.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
反序列化对象
反序列化是类似的。首先,我们分析一个流成Python原生类型...
import io
from rest_framework.parsers import JSONParser
stream = io.BytesIO(json)
data = JSONParser().parse(stream)
......那么,我们还原这些原生类型为验证数据的词典。
serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
节能实例
如果我们希望能够返回基于经过验证的数据完整的对象情况下,我们需要实现的一个或两个.create()
和.update()
方法。例如:
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
def create(self, validated_data):
return Comment(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
return instance
如果你的对象实例对应于Django模型,你还需要确保这些方法保存对象到数据库中。例如,如果Comment
是一个Django模型,方法可能是这样的:
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
现在,反序列化数据时,我们可以调用.save()
返回一个对象实例的基础上,经过验证的数据。
comment = serializer.save()
呼叫.save()
会创建一个新的实例,或更新现有的情况下,依靠,如果实例序列化类时,现有的实例通过了:
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
无论是.create()
和.update()
方法是可选的。您可以实现都不是,一个或两个人,根据不同的使用情况为您的序列化器类。
传递给其他属性 .save()
有时你会希望你的视图代码能够在保存实例的点注入额外的数据。这种额外的数据可能包括像当前用户,当前时间,或其他任何这不是请求数据的一部分信息。
你可以通过调用时,包括增加关键字参数这么做.save()
。例如:
serializer.save(owner=request.user)
任何额外的关键词参数将被包含在validated_data
参数时,.create()
或.update()
调用。
重写.save()
直接。
在某些情况下,.create()
和.update()
方法的名称可能是没有意义的。例如,在一个接触的形式,我们可能无法创建新实例,而是发送电子邮件或其他消息。
在这种情况下,你可能会转而选择覆盖.save()
直接,为更具可读性和有意义的。
例如:
class ContactForm(serializers.Serializer):
email = serializers.EmailField()
message = serializers.CharField()
def save(self):
email = self.validated_data['email']
message = self.validated_data['message']
send_email(from=email, message=message)
注意,在上述情况下,我们现在不必访问串行.validated_data
直接财产。
验证
当反序列化的数据,你总是需要调用is_valid()
试图访问的验证数据之前,或保存对象实例。如果发生任何验证错误,该.errors
属性将包含表示所得到的错误消息的字典。例如:
serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}
在字典中的每个关键将是字段名,和值将对应于该领域的任何错误消息的字符串列表。该non_field_errors
键也可能存在,并列出任何一般验证错误。该名称non_field_errors
键可以使用定制NON_FIELD_ERRORS_KEY
REST架构设置。
当反序列化的项目列表,错误将返回为代表每个反序列化项目的词典列表。
提高对无效数据异常
该.is_valid()
方法有一个可选的raise_exception
标志,这将导致它提出一个serializers.ValidationError
,如果有验证错误例外。
这些异常是由默认的异常处理程序REST框架提供了自动处理,并且将返回HTTP 400 Bad Request
默认响应。
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
字段级验证
您可以通过添加指定自定义字段级的验证.validate_<field_name>
方法,以你的Serializer
子类。这些都是类似.clean_<field_name>
的Django表单的方法。
这些方法需要一个单一的参数,它是字段值,需要验证。
你的validate_<field_name>
方法应该返回验证值或养serializers.ValidationError
。例如:
from rest_framework import serializers
class BlogPostSerializer(serializers.Serializer):
title = serializers.CharField(max_length=100)
content = serializers.CharField()
def validate_title(self, value):
"""
Check that the blog post is about Django.
"""
if 'django' not in value.lower():
raise serializers.ValidationError("Blog post is not about Django")
return value
注:如果您<field_name>
在使用参数的串行声明就是required=False
那么如果不包括外地此验证步骤将不会发生。
对象级检验
要做到这一点,需要访问多个字段的任何其他验证,添加一个名为方法.validate()
到您的Serializer
子类。此方法采用单个参数,该参数是字段值的字典。这应引起serializers.ValidationError
,如果有必要,或只返回验证值。例如:
from rest_framework import serializers
class EventSerializer(serializers.Serializer):
description = serializers.CharField(max_length=100)
start = serializers.DateTimeField()
finish = serializers.DateTimeField()
def validate(self, data):
"""
Check that start is before finish.
"""
if data['start'] > data['finish']:
raise serializers.ValidationError("finish must occur after start")
return data
验证器
在串行各个字段,包括校验,宣称他们在球场上的实例,例如:
def multiple_of_ten(value):
if value % 10 != 0:
raise serializers.ValidationError('Not a multiple of ten')
class GameRecord(serializers.Serializer):
score = IntegerField(validators=[multiple_of_ten])
...
串行器类也可以包括被施加到整套场数据的可重复使用的验证器。这些验证是通过声明它们的内部包含Meta
类,如下所示:
class EventSerializer(serializers.Serializer):
name = serializers.CharField()
room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
date = serializers.DateField()
class Meta:
# Each room only has one event per day.
validators = UniqueTogetherValidator(
queryset=Event.objects.all(),
fields=['room_number', 'date']
)
欲了解更多信息,请参阅验证文档。
访问初始数据和实例
当通过初始对象或查询集到串行器实例,该对象将提供如.instance
。如果没有初始对象传递,则.instance
属性会None
。
当将数据传递到串行的实例,未被修改的数据将提供作为.initial_data
。如果数据关键字参数不那么传递的.initial_data
属性将不存在。
部分更新
默认情况下,串行器必须传递值所有必填字段,否则将提高验证错误。您可以使用partial
参数,以允许部分更新。
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True)
嵌套处理对象
前面的例子是处理仅具有简单的数据类型的对象很好,但有时我们也需要能够代表更复杂的对象,一些对象的属性,可能不是简单数据类型,如字符串,日期或整数。
所述Serializer
类本身的类型Field
,并且可以用于表示其中一个对象类型嵌套在另一个关系。
class UserSerializer(serializers.Serializer):
email = serializers.EmailField()
username = serializers.CharField(max_length=100)
class CommentSerializer(serializers.Serializer):
user = UserSerializer()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
如果嵌套表示可以选择接受该None
值,你应该传递required=False
标志嵌套串行器。
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False) # May be an anonymous user.
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
同样,如果一个嵌套的表示应该是项目的列表,你应该通过many=True
标志来嵌套的序列化。
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False)
edits = EditItemSerializer(many=True) # A nested list of 'edit' items.
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
可写嵌套交涉
当与支持反序列化数据的嵌套表示处理,与嵌套对象的任何错误都会在嵌套对象的字段名被嵌套。
serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']}
类似地,.validated_data
属性将包括嵌套的数据结构。
写.create()
嵌套的表示方法
如果你支持嵌套写你交涉就需要编写.create()
或.update()
方法来处理保存多个对象。
下面的示例演示了如何处理创建与嵌套的配置文件对象的用户。
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
写.update()
嵌套的表示方法
对于更新你要仔细考虑如何处理更新的关系。例如,如果针对的关系的数据None
,或不提供时,应发生的以下的?
- 设置关系到
NULL
数据库中。 - 删除相关的实例。
- 忽略的数据和离开的实例,因为它是。
- 提高验证错误。
下面是一个例子.update()
在我们以前的方法UserSerializer
类。
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile')
# Unless the application properly enforces that this field is
# always set, the following could raise a `DoesNotExist`, which
# would need to be handled.
profile = instance.profile
instance.username = validated_data.get('username', instance.username)
instance.email = validated_data.get('email', instance.email)
instance.save()
profile.is_premium_member = profile_data.get(
'is_premium_member',
profile.is_premium_member
)
profile.has_support_contract = profile_data.get(
'has_support_contract',
profile.has_support_contract
)
profile.save()
return instance
由于嵌套的行为创建和更新可以是不明确的,并且可能需要相关模型之间复杂的依赖关系,REST框架3需要你总是明确写入这些方法。默认ModelSerializer
.create()
和.update()
方法不包括可写嵌套表示支持。
然而,存在着可用的第三方软件包,如DRF可写嵌套支持自动写入嵌套表示。
节省处理相关实例模型管理器类
在串行保存多个相关实例另一种方法是编写自定义模型管理器类,负责创建正确的实例。
例如,假设我们希望确保User
实例和Profile
实例总是一起创建为一对。我们可以写一个自定义的管理类,看起来是这样的:
class UserManager(models.Manager):
...
def create(self, username, email, is_premium_member=False, has_support_contract=False):
user = User(username=username, email=email)
user.save()
profile = Profile(
user=user,
is_premium_member=is_premium_member,
has_support_contract=has_support_contract
)
profile.save()
return user
这个管理器类现在越来越很好地概括了用户实例和配置文件实例在同一时间总是创建。我们.create()
在串行类的方法,现在可以重新编写,使用新的管理器方法。
def create(self, validated_data):
return User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
is_premium_member=validated_data['profile']['is_premium_member'],
has_support_contract=validated_data['profile']['has_support_contract']
)
有关此方法的更多信息请参阅Django文档模型管理员,并利用模型和管理类我这篇文章。
与多个对象处理
该Serializer
班还可以处理序列化或反序列化对象的列表。
序列化多个对象
序列化查询集或对象而不是一个对象实例的列表,你应该通过many=True
实例串行时标志。然后,您可以通过一个查询集或对象的名单被序列化。
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
# {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
# {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
# {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]
反序列化多个对象
对于反序列化多个对象的默认行为是支持多个对象的创建,但不支持多对象更新。有关如何支持或自定义这两种情况的更多信息,请参阅ListSerializer下面的文档。
包括额外的上下文
有些情况下,你需要提供额外的上下文串行除了对象被序列化。一种常见的情况是,如果您使用的是串行器,包括超链接的关系,这就需要串行有权访问当前请求,这样它才能正常产生完全合格的URL。
你可以通过一个提供任意附加的上下文context
实例序列化时的说法。例如:
serializer = AccountSerializer(account, context={'request': request})
serializer.data
# {'id': 6, 'owner': 'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}
上下文字典可以任何串行化逻辑字段内使用,如自定义.to_representation()
的方法,通过访问self.context
属性。
ModelSerializer
通常你会想串类,紧密映射到Django的模型定义。
本ModelSerializer
类提供了一个快捷方式,可以让你自动创建一个Serializer
类的字段对应示范场。
该ModelSerializer班是一样的常规Serializer类,不同之处在于:
- 它会自动生成一组为您的字段,基于模型的。
- 它会自动生成序列化验证,如unique_together验证。
- 它包括简单的默认实现
.create()
和.update()
。
声明ModelSerializer
如下所示:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
默认情况下,在类的所有模型字段将被映射到相应的串行器领域。
如在模型外键的任何关系,将映射到PrimaryKeyRelatedField
。除非作为规定明确包含反向关系并不默认包含串行关系的文件。
一检查 ModelSerializer
串行类产生有益的冗长表示字符串,使您可以全面检查各自领域的状态。这与工作时特别有用ModelSerializers
,你要确定哪些字段集的和验证是为你而自动创建。
要做到这一点,打开Django的外壳,使用python manage.py shell
,然后导入序列化器类,实例化,并打印对象表示...
>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
AccountSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
指定哪些字段包括
如果你只是想在一个模型序列化使用的默认字段的一个子集,你可以这样做,使用fields
或exclude
选择,就像你用ModelForm
。我们强烈建议您明确设置应使用序列化的所有字段fields
属性。这将使导致它不太可能无意中公开数据时,您的模型变化。
例如:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
您还可以将设置fields
属性的特殊值'__all__'
,表明模型中的所有字段应该使用。
例如:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
您可以设置exclude
属性字段列表从串行被排除。
例如:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
exclude = ['users']
在上面的例子中,如果Account
模型具有3个字段account_name
,users
和created
,这将导致在字段account_name
和created
被序列化。
在名称fields
和exclude
属性,通常会映射到模型上的模型类的字段。
或者在名称fields
选项可以映射到属性或没有参数的模型类存在的方法。
自从3.3.0版本,它是强制性的,提供的属性之一fields
或exclude
。
指定嵌套系列化
默认ModelSerializer
使用的关系主键,但你也可以很容易地使用产生嵌套表示depth
选项:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
depth = 1
的depth
选项应设置为一个整数值,表示应恢复到平坦的表示之前被遍历关系的深度。
如果您想自定义序列化完成的方式,你需要自己定义字段。
明确指定领域
您可以添加额外的字段到ModelSerializer
通过声明领域的阶级或覆盖默认域,就像你对一个Serializer
类。
class AccountSerializer(serializers.ModelSerializer):
url = serializers.CharField(source='get_absolute_url', read_only=True)
groups = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Account
额外的字段可以对应于在模型上的任何财产或调用。
指定只读域
您可能希望指定多个领域只读。相反,与明确添加每个字段的read_only=True
属性,你可以使用快捷元选项read_only_fields
。
这个选项应该是字段名称列表或元组,并声明如下:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
read_only_fields = ['account_name']
已模型字段editable=False
设置和AutoField
字段将被设置为只读在默认情况下,并不需要被添加到该read_only_fields
选项。
注意:有一种情况只读字段是一部分的特殊情况下,unique_together
在模型级约束。在这种情况下,字段由串行器类需要,以验证约束,但应该也不会被用户编辑。
对付这种正确的做法是明确指定在串行领域,同时提供了read_only=True
和default=…
关键字参数。
这样的一个例子是一个只读相对于当前被验证User
其是unique_together
与另一个标识符。在这种情况下,你会宣称,像这样的用户领域:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
请检查验证器的文档有关的详细信息UniqueTogetherValidator和CurrentUserDefault类。
额外的关键词参数
还有一个快捷方式,允许您在字段中指定的任意附加关键字参数,使用extra_kwargs
选项。作为的情况下read_only_fields
,这意味着你不需要显式声明在串行领域。
该选项是一本字典,映射字段名的参数的字典。例如:
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['email', 'username', 'password']
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User(
email=validated_data['email'],
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
请记住,如果该字段已明确在串行类中声明,那么extra_kwargs
选项将被忽略。
关系领域
当序列化模型实例,有一些你可能会选择代表的关系不同的方式。对于默认表示ModelSerializer
是使用相关实例的主键。
可选表示包括使用超链接,序列完整的嵌套表示序列化,或者用自定义序列化的表示。
有关详情请参阅串行关系的文件。
自定义字段映射
该ModelSerializer类也暴露了一个API,你可以为了改变如何实例串行时串行字段自动确定覆盖。
通常情况下,如果ModelSerializer
不产生需要通过默认的字段那么应该将它们添加到类明确,或者干脆使用常规Serializer
类代替。然而,在某些情况下,你可能要创建定义如何串行字段用于任何给定的模型创建一个新的基类。
.serializer_field_mapping
Django的模型类的映射到REST框架串行器类。您可以覆盖这个映射改变,应使用每个模型类的默认序列化类。
.serializer_related_field
此属性应该是串行领域类,即默认用于关系领域。
对于ModelSerializer
此默认为PrimaryKeyRelatedField
。
对于HyperlinkedModelSerializer
此默认为serializers.HyperlinkedRelatedField
。
serializer_url_field
应该用于任何串行器领域类url
的序列化领域。
默认为 serializers.HyperlinkedIdentityField
serializer_choice_field
应该用于在串行任何选择字段中的串行领域类。
默认为 serializers.ChoiceField
该field_class和field_kwargs API
下面的方法调用,以确定类和关键字参数为应自动包含在串行每个字段。所有这些方法应返回的二元组(field_class, field_kwargs)
。
.build_standard_field(self, field_name, model_field)
调用来生成映射到一个标准的模式场串行场。
默认实现返回基于串行类serializer_field_mapping
属性。
.build_relational_field(self, field_name, relation_info)
调用来生成映射到关系模型场串行场。
默认实现返回基于串行类serializer_related_field
属性。
该relation_info
参数是一个名为元组,包含model_field
,related_model
,to_many
和has_through_model
属性。
.build_nested_field(self, field_name, relation_info, nested_depth)
调用来生成映射到关系模型场,当一个串行场depth
选项设置。
默认的实现动态地创建基于任何一个嵌套的序列化器类ModelSerializer
或HyperlinkedModelSerializer
。
该nested_depth
会的价值depth
选择,减之一。
该relation_info
参数是一个名为元组,包含model_field
,related_model
,to_many
和has_through_model
属性。
.build_property_field(self, field_name, model_class)
叫以生成映射到模型上的类的属性或零参数方法的串行字段。
默认实现返回一个ReadOnlyField
类。
.build_url_field(self, field_name, model_class)
调用以产生串行自己的串行场url
场。默认实现返回一个HyperlinkedIdentityField
类。
.build_unknown_field(self, field_name, model_class)
当调用字段名没有映射到任何模型字段或模型属性。默认实现抛出一个错误,但子类可以定义此行为。
HyperlinkedModelSerializer
的HyperlinkedModelSerializer
类是类似于ModelSerializer
不同之处在于它使用的超链接来表示的关系,而不是主键类。
默认情况下,串行器将包括一个url
领域,而不是一个主键字段。
URL字段将使用表示HyperlinkedIdentityField
串行场,并在模型中的任何关系将使用表示HyperlinkedRelatedField
串行场。
你可以将它添加到明确包括主键fields
的选项,例如:
class AccountSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Account
fields = ['url', 'id', 'account_name', 'users', 'created']
绝对和相对URL
当实例化一个HyperlinkedModelSerializer
必须包含在当前 request
的背景下串行,例如:
serializer = AccountSerializer(queryset, context={'request': request})
这样做将确保该超链接可包括适当的主机名,使得所得到的表示使用完全限定的URL,例如:
http://api.example.com/accounts/1/
而不是相对URL,例如:
/accounts/1/
如果你不希望使用相对URL,你应该明确地传递{'request': None}
在串行环境。
如何超链接的意见确定
需要有确定哪些意见应该用于超链接到模型实例的方式。
默认情况下,超链接,预计相当于将风格相匹配的视图名称'{model_name}-detail'
由,并查找实例pk
关键字参数。
您可以覆盖一个URL字段视图名称和通过使用查阅字段,或两者中,view_name
并lookup_field
在选项extra_kwargs
设置,如下所示:
class AccountSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Account
fields = ['account_url', 'account_name', 'users', 'created']
extra_kwargs = {
'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},
'users': {'lookup_field': 'username'}
}
或者您可以明确设置在串行领域。例如:
class AccountSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='accounts',
lookup_field='slug'
)
users = serializers.HyperlinkedRelatedField(
view_name='user-detail',
lookup_field='username',
many=True,
read_only=True
)
class Meta:
model = Account
fields = ['url', 'account_name', 'users', 'created']
提示:正确匹配在一起,超链接的陈述和您的URL的conf有时可以是一个有点繁琐。打印repr
一个的HyperlinkedModelSerializer
实例来检查到底是哪视图名和查询领域的关系预计将映射过一个特别有用的方法。
更改URL字段名
URL字段默认为“URL”的名称。您可以在全球覆盖此,通过使用URL_FIELD_NAME
设置。
ListSerializer
本ListSerializer
类提供了序列化和一次验证多个对象的行为。你不会通常需要使用ListSerializer
直接,而是应该简单地传递many=True
实例化一个序列化时。
当一个串行被实例化和many=True
传递,一个ListSerializer
实例将被创建。串行器类便成为父母的孩子ListSerializer
以下参数也可以被传递给一个ListSerializer
字段或传递串行many=True
:
allow_empty
这是True
默认,但可以设置为False
你希望禁止空列表作为有效输入。
定制ListSerializer
行为
这里是一些使用情况下,您可能希望定制的ListSerializer
行为。例如:
- 你要提供的列表,如检查到一个元素没有与在列表中的其他元素冲突的特定验证。
- 要自定义多个对象的创建或更新行为。
对于这些情况,您可以修改时所使用的类many=True
被传递,通过list_serializer_class
在串行选项Meta
类。
例如:
class CustomListSerializer(serializers.ListSerializer):
...
class CustomSerializer(serializers.Serializer):
...
class Meta:
list_serializer_class = CustomListSerializer
自定义多个创建
多个对象创建默认的实现是简单地调用.create()
列表中的每个项目。如果你想定制这一行为,则需要自定义.create()
的方法ListSerializer
时所使用的类many=True
传递。
例如:
class BookListSerializer(serializers.ListSerializer):
def create(self, validated_data):
books = [Book(**item) for item in validated_data]
return Book.objects.bulk_create(books)
class BookSerializer(serializers.Serializer):
...
class Meta:
list_serializer_class = BookListSerializer
自定义多个更新
默认情况下,ListSerializer
类不支持多个更新。这是因为中能获得的插入和删除行为是不明确的。
为了支持多个更新,你需要明确这样做。在编写多个更新代码,请务必牢记以下情况:
- 你如何确定哪个实例应该在数据列表中的每个项目进行更新?
- 应该如何插入处理?他们是无效的,还是他们创建新的对象?
- 应该如何清除处理?他们是否意味着对象删除或移除有关系吗?他们应该被忽略,或者是他们无效?
- 应该如何排序处理?是否改变两个项目的位置暗示任何状态变化,或者它忽略?
您将需要一个明确的加id
场到实例序列化。默认隐含产生的id
场被标记为read_only
。这将导致它被更新上去除。一旦你明确声明它,它就会出现在列表中序列化的可用update
方法。
这里有一个如何选择实现多个更新的例子:
class BookListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
# Maps for id->instance and id->data item.
book_mapping = {book.id: book for book in instance}
data_mapping = {item['id']: item for item in validated_data}
# Perform creations and updates.
ret = []
for book_id, data in data_mapping.items():
book = book_mapping.get(book_id, None)
if book is None:
ret.append(self.child.create(data))
else:
ret.append(self.child.update(book, data))
# Perform deletions.
for book_id, book in book_mapping.items():
if book_id not in data_mapping:
book.delete()
return ret
class BookSerializer(serializers.Serializer):
# We need to identify elements in the list using their primary key,
# so use a writable field here, rather than the default which would be read-only.
id = serializers.IntegerField()
...
class Meta:
list_serializer_class = BookListSerializer
这是可能的第三方软件包可以被包括沿着3.1发行版,提供了一种用于多个更新操作,类似于一些自动支持allow_add_remove
,这是存在于REST框架2的行为。
定制ListSerializer初始化
当一个串行与many=True
被实例化,我们需要确定哪些参数和关键字参数应传递给.__init__()
了孩子两个方法Serializer
类,并父ListSerializer
类。
默认的实现是将所有参数传递给这两个类,除了validators
和任何自定义关键字参数,假设这两者是打算为孩子序列化器类。
有时候,你可能需要明确指定如何在孩子和父母类应该被实例化many=True
传递。您可以通过这样做many_init
类方法。
@classmethod
def many_init(cls, *args, **kwargs):
# Instantiate the child serializer.
kwargs['child'] = cls()
# Instantiate the parent list serializer.
return CustomListSerializer(*args, **kwargs)
BaseSerializer
BaseSerializer
类,可用于轻松支持替代序列化和反序列化的风格。
这个类实现了相同的基本API的Serializer
类:
.data
- 返回传出原始表示。.is_valid()
- 反序列化和验证传入的数据。.validated_data
- 返回验证输入的数据。.errors
- 验证期间返回的任何错误。.save()
- 持续经过验证的数据转换成对象实例。
有四种方法可以被覆盖,这取决于你想要什么功能,串行器类,以支持:
.to_representation()
- 覆盖这支持系列化,对于读操作。.to_internal_value()
- 覆盖这支持反序列化,用于写操作。.create()
和.update()
-覆盖一个或两个的这些支持节能实例。
因为这个类提供了相同的接口Serializer
类,可以与现有通用的基于类的看法完全一样,你会为一个普通使用Serializer
或ModelSerializer
。
这样做的时候,你会注意到的唯一区别是BaseSerializer
类不会产生可浏览API的HTML表单。这是因为它们返回的数据不包括所有的字段信息,将允许每个字段被渲染成合适的HTML输入。
只读BaseSerializer
类
要使用实现只读串BaseSerializer
类,我们只需要重写.to_representation()
方法。让我们用一个简单的Django模型来看看一个例子:
class HighScore(models.Model):
created = models.DateTimeField(auto_now_add=True)
player_name = models.CharField(max_length=10)
score = models.IntegerField()
这是简单的创建一个只读串行转换HighScore
的实例为基本数据类型。
class HighScoreSerializer(serializers.BaseSerializer):
def to_representation(self, instance):
return {
'score': instance.score,
'player_name': instance.player_name
}
现在,我们可以使用这个类来序列化单HighScore
实例:
@api_view(['GET'])
def high_score(request, pk):
instance = HighScore.objects.get(pk=pk)
serializer = HighScoreSerializer(instance)
return Response(serializer.data)
或者用它来序列化的多个实例:
@api_view(['GET'])
def all_high_scores(request):
queryset = HighScore.objects.order_by('-score')
serializer = HighScoreSerializer(queryset, many=True)
return Response(serializer.data)
读写BaseSerializer
班
要创建一个读写串行器来实现,我们首先需要.to_internal_value()
方法。此方法返回将被用于构造对象实例的验证值,并且可能会产生一种serializers.ValidationError
如果所提供的数据是在一个不正确的格式。
一旦你已经实现.to_internal_value()
,基本验证API将可在串行器,你将能够使用.is_valid()
,.validated_data
和.errors
。
如果你也想支持.save()
你还需要落实的一方或双方.create()
和.update()
方法。
下面是我们以前的一个完整的例子HighScoreSerializer
,这是被更新为同时支持读取和写入操作。
class HighScoreSerializer(serializers.BaseSerializer):
def to_internal_value(self, data):
score = data.get('score')
player_name = data.get('player_name')
# Perform the data validation.
if not score:
raise serializers.ValidationError({
'score': 'This field is required.'
})
if not player_name:
raise serializers.ValidationError({
'player_name': 'This field is required.'
})
if len(player_name) > 10:
raise serializers.ValidationError({
'player_name': 'May not be more than 10 characters.'
})
# Return the validated values. This will be available as
# the `.validated_data` property.
return {
'score': int(score),
'player_name': player_name
}
def to_representation(self, instance):
return {
'score': instance.score,
'player_name': instance.player_name
}
def create(self, validated_data):
return HighScore.objects.create(**validated_data)
创建新的基类
的BaseSerializer
,如果你想实现新的通用串行类来处理特定的序列化的风格,或者使用可替换存储后端集成类也是有用的。
下面的类是一个通用串行能够处理强迫任意对象到原始的表示的示例。
class ObjectSerializer(serializers.BaseSerializer):
"""
A read-only serializer that coerces arbitrary complex objects
into primitive representations.
"""
def to_representation(self, instance):
output = {}
for attribute_name in dir(instance):
attribute = getattr(instance, attribute_name)
if attribute_name.startswith('_'):
# Ignore private attributes.
pass
elif hasattr(attribute, '__call__'):
# Ignore methods and other callables.
pass
elif isinstance(attribute, (str, int, bool, float, type(None))):
# Primitive types can be passed through unmodified.
output[attribute_name] = attribute
elif isinstance(attribute, list):
# Recursively deal with items in lists.
output[attribute_name] = [
self.to_representation(item) for item in attribute
]
elif isinstance(attribute, dict):
# Recursively deal with items in dictionaries.
output[attribute_name] = {
str(key): self.to_representation(value)
for key, value in attribute.items()
}
else:
# Force anything else to its string representation.
output[attribute_name] = str(attribute)
return output
先进的串行器使用
重写序列化和反序列化行为
如果您需要更改序列化器类的序列化和反序列化的行为,你可以通过重写这样做.to_representation()
或.to_internal_value()
方法。
一些原因,这可能是有用的包括...
- 添加新的串行基类新的行为。
- 修改行为略有现有的类。
- 提高序列化表现为频繁访问的API端点返回大量数据的。
对于这些方法的签名如下:
.to_representation(self, instance)
注意到,需要序列化,而应返回原表示对象实例。通常,这意味着返回的结构,内置Python数据类型。可以处理将取决于具体类型的渲染,你已经配置了您的API类。
可能会被改写,以便修改代表性风格。例如:
def to_representation(self, instance):
"""Convert `username` to lowercase."""
ret = super().to_representation(instance)
ret['username'] = ret['username'].lower()
return ret
.to_internal_value(self, data)
注意到未经验证的输入数据作为输入,并应该返回将提供作为验证数据serializer.validated_data
。返回值也将被传递到.create()
或.update()
方法,如果.save()
被调用的序列化器类。
如果任何验证失败,则该方法应引起serializers.ValidationError(errors)
。该errors
参数应该是一个字典映射字段名称(或settings.NON_FIELD_ERRORS_KEY
)到错误消息的列表。如果你不需要改变反序列化的行为,而是要提供对象级验证,我们建议你,而不是覆盖.validate()
方法。
该data
传递给此方法的参数一般会的价值request.data
,所以它提供的数据类型将取决于您配置您的API的解析器类。
串行继承
到Django的形式类似,您可以扩展和通过继承重用序列化。这允许你声明一组通用,然后可以在许多串行器的使用在父类的字段或方法。例如,
class MyBaseSerializer(Serializer):
my_field = serializers.CharField()
def validate_my_field(self, value):
...
class MySerializer(MyBaseSerializer):
...
像Django的Model
和ModelForm
类,内Meta
上串行类不隐式地从它的父母的内部继承Meta
类。如果你想Meta
从一个父类的类继承,你必须明确地这样做。例如:
class AccountSerializer(MyBaseSerializer):
class Meta(MyBaseSerializer.Meta):
model = Account
通常我们会建议不使用的内部元类的继承,而是宣布所有选项明确。
此外,以下注意事项适用于串行继承:
-
Python的名称解析规则。如果你有一个声明多个基类
Meta
的内部类,只有第一个将被使用。这意味着孩子的Meta
,如果它存在,否则Meta
第一个父等 -
这是可能的声明删除
Field
通过设置名称是从父类继承None
的子类。class MyBaseSerializer(ModelSerializer): my_field = serializers.CharField() class MySerializer(MyBaseSerializer): my_field = None
但是,你只能使用此技术从一个父类声明的方式定义字段选择退出; 它不会阻止
ModelSerializer
从生成默认字段。选择退出的默认字段,请参阅指定哪些字段包含。
动态修改字段
一旦串行器已经被初始化,被在串行设置的字段的词典可以使用来访问.fields
属性。访问和修改这个属性允许你动态修改串行器。
修改fields
参数,直接让你做有趣的事情,如改变对串行场的参数在运行时,而不是在声明串行点。
例
例如,如果你希望能够到哪些字段应该由串行器在初始化的时候用于设置,您就可以创建这样一个序列化器类:
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
然后,这将允许你做到以下几点:
>>> class UserSerializer(DynamicFieldsModelSerializer):
>>> class Meta:
>>> model = User
>>> fields = ['id', 'username', 'email']
>>>
>>> print(UserSerializer(user))
{'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'}
>>>
>>> print(UserSerializer(user, fields=('id', 'email')))
{'id': 2, 'email': 'jon@example.com'}
自定义默认域
REST框架2提供了一个API,允许开发人员覆盖对ModelSerializer
类将自动生成字段的默认设置。
该API包括.get_field()
,.get_pk_field()
和其他方法。
由于串行有3.0得到根本重新设计这个API不再存在。你还可以修改获得创建领域,但你需要参考的源代码,并意识到,如果所做的更改都反对API的私人位,然后他们可能会有所变动。
第三方软件包
下面的第三方软件包也可提供。
Django的REST棉花糖
的django的静止-棉花糖软件包提供了序列化器的替换实现中,使用Python 棉花糖库。它暴露了相同的API REST框架序列化,并且可以作为一个下拉更换部分使用情况。
Serpy
该serpy包是是为速度而序列化的另一种实现。Serpy序列化复杂数据类型,以简单的原生类型。天然类型可以容易地转化为JSON或任何其他格式需要的。
MongoengineModelSerializer
的django的静止框架-mongoengine包提供了一个MongoEngineModelSerializer
在使用的MongoDB作为Django的REST框架存储层支持串行器类。
GeoFeatureModelSerializer
在Django的REST的架构的GIS包提供了一个GeoFeatureModelSerializer
支持GeoJSON的无论是读取和写入操作序列化器类。
HStoreSerializer
在Django的REST的架构,hstore包提供了HStoreSerializer
支持Django的hstore DictionaryField
模型场及其schema-mode
功能。
动态REST
的动态其余包延伸ModelSerializer和ModelViewSet接口,加入API查询参数,用于过滤,排序,以及包括/排除通过您的串行定义的所有字段和关系。
动态字段密新
的DRF-动态场包提供一个混合动态地限制每个串行化器中的字段由一个URL参数指定的子集。
DRF弹性域
该DRF-FLEX-场包扩展ModelSerializer和ModelViewSet以动态设置字段和扩大原始字段嵌套模型,无论是从URL参数和您的序列化器类定义提供了常用的功能。
串行扩展
在Django的休息框架串的扩展 包提供的工具集,干涸的序列化,通过允许在每个视图/请求的基础定义的字段。字段可以被列入白名单,黑名单和子序列化可以任意扩展。
HTML表单JSON
的HTML的JSON-形式包提供了用于处理的算法并串行<form>
每(不活动)提交HTML表格JSON规范。串行器功能有助于内HTML任意嵌套JSON结构的处理。例如,<input name="items[0][id]" value="5">
将被解释为{"items": [{"id": "5"}]}
。
DRF-的Base64
DRF-Base64编码提供了一组现场和模型串行的,处理的base64编码文件上传。
QueryFields
djangorestframework-queryfields允许API客户机指定哪个字段将在经由入选/排除查询参数的响应被发送。
DRF可写嵌套
的DRF-可写-可嵌套包提供可写的嵌套模型序列化器,它允许创建具有嵌套相关数据/更新的模型。