DRF-序列化器
Serializer序列化
声明序列化器
声明一个序列化器看起来非常类似于声明一个表单:
from rest_framework import serializers
classCommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
保存实例
如果我们希望能够基于经过验证的数据返回完整的对象实例,我们需要实现一个或两个.create()
and.update()
方法。例如:
classCommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
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)
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()
. 例如:
serializer.save(owner=request.user)
验证
反序列化数据时,您始终需要is_valid()
在尝试访问已验证数据或保存对象实例之前调用。如果发生任何验证错误,该.errors
属性将包含一个字典,表示生成的错误消息。例如:
字段级验证
.validate_<field_name>
您可以通过向子类添加方法来指定自定义字段级验证Serializer
。这些类似于.clean_<field_name>
Django 表单上的方法。
这些方法采用单个参数,即需要验证的字段值。
您的validate_<field_name>
方法应该返回经过验证的值或引发serializers.ValidationError
. 例如:
from rest_framework import serializers
classBlogPostSerializer(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'notin value.lower():
raise serializers.ValidationError("Blog post is not about Django")
return value
注意: 如果您<field_name>
在序列化程序上声明了参数,required=False
则如果不包含该字段,则不会执行此验证步骤。
对象级验证
要执行需要访问多个字段的任何其他验证,请添加一个调用.validate()
到您的Serializer
子类的方法。此方法采用单个参数,即字段值字典。serializers.ValidationError
如有必要,它应该引发 a ,或者只返回经过验证的值。例如:
from rest_framework import serializers
classEventSerializer(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')
classGameRecord(serializers.Serializer):
score =IntegerField(validators=[multiple_of_ten])
...
序列化程序类还可以包括应用于完整字段数据集的可重用验证器。这些验证器通过在内部Meta
类中声明它们来包含,如下所示:
classEventSerializer(serializers.Serializer):
name = serializers.CharField()
room_number = serializers.IntegerField(choices=[101,102,103,201])
date = serializers.DateField()
classMeta:
# Each room only has one event per day.
validators =[
UniqueTogetherValidator(
queryset=Event.objects.all(),
fields=['room_number','date']
)
]
有关更多信息,请参阅验证器文档。
访问初始数据和实例
将初始对象或查询集传递给序列化程序实例时,该对象将以.instance
. 如果没有传递初始对象,则.instance
属性将为None
.
将数据传递给序列化程序实例时,未修改的数据将以.initial_data
. 如果data
未传递关键字参数,则该.initial_data
属性将不存在。
部分更新
默认情况下,序列化程序必须为所有必填字段传递值,否则它们会引发验证错误。您可以使用该partial
参数以允许部分更新。
# Update `comment` with partial data
serializer =CommentSerializer(comment, data={'content':'foo bar'},partial=True)
处理嵌套对象
前面的示例适用于处理只有简单数据类型的对象,但有时我们还需要能够表示更复杂的对象,其中对象的某些属性可能不是简单的数据类型,例如字符串、日期或整数。
该类Serializer
本身是 的一种类型Field
,可用于表示一个对象类型嵌套在另一个对象类型中的关系。
classUserSerializer(serializers.Serializer):
email = serializers.EmailField()
username = serializers.CharField(max_length=100)
classCommentSerializer(serializers.Serializer):
user =UserSerializer()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
如果嵌套表示可以选择接受该None
值,则应将required=False
标志传递给嵌套序列化程序。
classCommentSerializer(serializers.Serializer):
user =UserSerializer(required=False)# May be an anonymous user.
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
同样,如果嵌套表示应该是项目列表,则应将many=True
标志传递给嵌套序列化程序。
classCommentSerializer(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()
处理保存多个对象的方法。
以下示例演示了如何使用嵌套的配置文件对象创建用户。
classUserSerializer(serializers.ModelSerializer):
profile =ProfileSerializer()
classMeta:
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 framework 3 要求您始终明确地编写这些方法。默认值ModelSerializer
.create()
和.update()
方法不包括对可写嵌套表示的支持。
但是,有第三方包可用,例如支持自动可写嵌套表示的DRF Writable Nested 。
ModelSerializer模型序列化器
该ModelSerializer
类与普通Serializer
课程相同,除了 :
- 它将根据模型自动为您生成一组字段。
- 它将自动为序列化程序生成验证器,例如 unique_together 验证器。
.create()
它包括和的简单默认实现.update()
。
声明 aModelSerializer
看起来像这样:
classAccountSerializer(serializers.ModelSerializer):
classMeta:
model =Account
fields =['id','account_name','users','created']
指定包含字段
如果您只想在模型序列化程序中使用默认字段的子集,则可以使用fields
orexclude
选项来实现
从 3.3.0 版开始,必须提供属性之一fields
或exclude
.
字段扩展与重写
通过在类上声明字段来向 a 添加额外字段ModelSerializer
或覆盖默认字段
指定只读字段
您可能希望将多个字段指定为只读。read_only=True
您可以使用快捷方式 Meta 选项,而不是使用属性显式添加每个字段read_only_fields
。
已editable=False
设置的模型字段,和AutoField
字段默认设置为只读,不需要添加到read_only_fields
选项中。
附加关键字参数
还有一个快捷方式允许您使用该extra_kwargs
选项在字段上指定任意附加关键字参数。与 的情况一样read_only_fields
,这意味着您不需要在序列化程序上显式声明该字段。
此选项是一个字典,将字段名称映射到关键字参数的字典。例如:
classCreateUserSerializer(serializers.ModelSerializer):
classMeta:
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
选项将被忽略。
序列化器字段
read_only
只读字段包含在 API 输出中,但不应包含在创建或更新操作期间的输入中。任何错误地包含在序列化程序输入中的“read_only”字段都将被忽略。
设置此项以True
确保在序列化表示时使用该字段,但在反序列化期间创建或更新实例时不使用该字段。
默认为False
write_only
设置此项以True
确保在更新或创建实例时可以使用该字段,但在序列化表示时不包括在内。
默认为False
required
如果在反序列化期间未提供字段,通常会引发错误。如果在反序列化期间不需要此字段,则设置为 false。
将此设置为False
还允许在序列化实例时从输出中省略对象属性或字典键。如果密钥不存在,它将根本不包含在输出表示中。
默认为True
. 如果您使用模型序列化程序,默认值将是False
如果您在.blank=True``default``null=True``Model
default
如果设置,如果没有提供输入值,这将给出将用于该字段的默认值。如果未设置,则默认行为是根本不填充属性。
在default
部分更新操作期间不应用。在部分更新的情况下,只有传入数据中提供的字段才会返回经过验证的值。
可以设置为函数或其他可调用对象,在这种情况下,每次使用时都会评估该值。调用时,它将不接收任何参数。如果可调用对象具有requires_context = True
属性,则序列化器字段将作为参数传递。
例如:
classCurrentUserDefault:
"""
May be applied as a `default=...` value on a serializer field.
Returns the current user.
"""
requires_context =True
def __call__(self, serializer_field):
return serializer_field.context['request'].user
序列化实例时,如果实例中不存在对象属性或字典键,则将使用默认值。
请注意,设置一个default
值意味着该字段不是必需的。同时包含 thedefault
和required
关键字参数是无效的,并且会引发错误。
allow_null
None
如果传递给序列化器字段,通常会引发错误。将此关键字参数设置为True
ifNone
应被视为有效值。
请注意,如果没有明确的default
,将此参数设置为True
将意味着序列化输出的default
值null
,但并不意味着输入反序列化的默认值。
默认为False
验证器
当前用户默认值
可用于表示当前用户的默认类。为了使用它,必须在实例化序列化程序时将“请求”作为上下文字典的一部分提供。
owner = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
CreateOnlyDefault
一个默认类,可用于 在创建操作期间仅设置默认参数 。在更新期间,该字段被省略。
它接受一个参数,这是在创建操作期间应使用的默认值或可调用对象。
created_at = serializers.DateTimeField(
default=serializers.CreateOnlyDefault(timezone.now)
)
唯一验证器
此验证器可用于unique=True
对模型字段实施约束。它需要一个必需参数和一个可选messages
参数:
queryset
required - 这是应该强制执行唯一性的查询集。message
- 验证失败时应使用的错误消息。lookup
- 用于查找具有正在验证的值的现有实例的查找。默认为'exact'
.
此验证器应应用于 序列化器字段 ,如下所示:
from rest_framework.validators importUniqueValidator
slug =SlugField(
max_length=100,
validators=[UniqueValidator(queryset=BlogPost.objects.all())]
)
UniqueTogetherValidator
此验证器可用于unique_together
对模型实例实施约束。它有两个必需参数和一个可选messages
参数:
queryset
required - 这是应该强制执行唯一性的查询集。fields
required - 字段名称的列表或元组,应构成唯一集。这些必须作为序列化程序类的字段存在。message
- 验证失败时应使用的错误消息。
验证器应应用于 序列化程序类 ,如下所示:
from rest_framework.validators importUniqueTogetherValidator
classExampleSerializer(serializers.Serializer):
# ...
classMeta:
# ToDo items belong to a parent list, and have an ordering defined
# by the 'position' field. No two items in a given list may share
# the same position.
validators =[
UniqueTogetherValidator(
queryset=ToDoItem.objects.all(),
fields=['list','position']
)
]