前言
官方文档是最好的参考,这里是官方文档的部分内容,如总结有误,请查阅官方文档。
Serializers
序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生Python数据类型,然后可以将它 们轻松地呈现为 JSON , XML 或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。
REST framework中的序列化类与Django 的Form和ModelForm 类非常相似。我们提 供了一个Serializer类,它提供了一种强大的通用方法来控制响应的输出,以及一个ModelSerializer类,它为创建处理模型实例和查询集的序列化提供了有效的快捷方式。
序列化对象:将python原生数据,渲染为数据流,如json
反序列化对象:将数据流,如json,转化为python原生数据类型
保存实例
如果希望能够基于验证的数据返回完整的对象实例,则需要实现.create() 和.update() 方 法中的一个或两个。即重写 .create()和.update()的方法。
当反序列化数据时,我们可以调用 .save() 根据验证的数据返回一个对象实例。
调用 .save() 将创建一个新实例或更新现有实例,具体取决于在实例化序列化类时是否传递了现 有实例:
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
这两个方法是可选的,需要根据实际功能进行选择。save可以重写,让他具有实际功能:
1、将附加属性传递给 .save()
有时你会希望你的视图代码能够在保存实例的时候注入额外的数据。这些附加数据可能包含当前用户, 当前时间或其他任何不属于请求数据的信息:
serializer.save(owner=request.user)
2、直接覆盖 .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)
如上,该功能不再是保存数据到数据库,而是发送邮件。在上面的情况下,必须直接访问 serializer .validated_data 属性。
验证
在反序列化数据时,你总是需要在尝试访问验证数据之前调用 is_valid() ,或者保存对象实例。 如果发生任何验证错误,那么 .errors 属性将包含一个代表错误消息的字典。
也就是说,在校验数据的时候,需要调用is_valid() 方法。校验会有一些等级:
1、字段级验证
可以通过向 Serializer 子类添加 .validate_<field_name> 方法来指定自定义字段级验 证。这些与 Django 表单上的 .clean_<field_name> 方法类似。
也就是在序列化器类里面按照上面的格式定义方法。
2、对象级验证
如果要对多个字段进行其他的验证,请将一个名为 .validate() 的方法添加到您的 Serializer 子类中。这个方法只有一个参数,它是一个字段值( field - value )的字典。
以上都是框架的规则,需要遵守规则来使用,至于实现,得看源码。
验证器
1、序列化器上的各个字段可以包含验证器,方法是在字段实例上声明它们:
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])
2、重用验证器,是通过在内部的 Meta 类 中声明它们来包含的:
class EventSerializer(serializers.Serializer):
...
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 提供。如果 data 关键字参 数未被传递,那么 .initial_data 属性将不存在。
部分更新
默认情况下,序列化程序必须为所有必填字段传递值,否则会引发验证错误。您可以使用 partial 参数以允许部分更新:
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'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()
如上,CommentSerializer的数据格式将为:{‘user’: {‘email’: ‘foobar’, ‘username’: ‘doe’}, ‘content’: ‘baz’},属于嵌套类型
如果嵌套对象可以是 None 值,则应将 required = False 标志传递给嵌套的序列化类。
同样,如果嵌套对象是一个列表,则应将 many = True 标志传递给嵌套的序列化类。
同样, .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 。
删除关联的实例。
忽略数据并保持原样。
引发验证错误。
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile')
profile = instance.profile
......
instance.save()
profile.is_premium_member = profile_data.get( 'is_premium_member', profile.is_premium_member ,)
profile.save()
return instance
因为嵌套创建和更新的行为可能不明确,并且可能需要相关模型之间的复杂依赖关系,所以 REST framework 3 要求你始终明确写入这些方法。默认的 ModelSerializer 的 .create() 和 .update() 方法不包括对可写嵌套表示的支持。
不过,有第三方软件包可用,如支持自动可写嵌套表示的 DRF Writable Nested。
在模型管理器类中保存相关的实例
,假设我们希望确保 User 实例和 Profile 实例始终作为一对创建。我们可能会编写一 个类似下面的自定义管理器类
class UserManager(models.Manager):
......
此管理器类现在更好地封装了用户实例和配置文件实例始终在同一时间创建.
处理多个对象&&反序列化多个对象
要序列化查询集或对象列表而不是单个对象实例,在实例化序列化类时,应该传递 many=True 标 志。然后,您可以传递要序列化的查询集或对象列表:
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
反序列化多个对象的默认行为是支持多个对象创建,但不支持多个对象更新。
除了被序列化的对象外,还有一些情况需要为序列化类提供额外的上下文。一种常见的情况是,如果你 使用的是包含超链接关系的序列化类,则需要序列化类访问当前请求,以便它可以正确生成完全限定的 URL。
ModelSerializer
ModelSerializer 类提供了一个快捷方式,可让你自动创建一个 Serializer 类,其中的字段 与模型类字段对应。
ModelSerializer 类与常规 Serializer 类相同,不同之处在于:
它会根据模型自动生成一组字段。
它会自动为序列化类生成验证器,例如 unique_together 验证器。
它包含 .create() 和 .update() 的简单默认实现。
默认情况下,该类中的所有模型类字段将被映射为相应的序列化类字段。
任何关系(如模型上的外键)都将映射到PrimaryKeyRelatedField 。除非在序列化关系文档中 指定,否则默认不包括反向关系。
序列化类能够生成一个表示字符串,可以让你充分检查其字段的状态。在使用 ModelSerializer 进行工作时,这是特别有用的,你需要确定它为你自动创建了哪些字段和验证器。
实例化它并打 印对象表示形式:
from myapp.serializers import AccountSerializer
serializer = AccountSerializer()
print(repr(serializer))
指定要包含的字段:如果你只希望在模型序列化程序中使用默认字段的子集,则可以使用 fields 或 exclude 选 项来完成此操作,就像使用 ModelForm 一样。强烈建议你显式使用 fields 属性序列化的所 有字段。这将使你不太可能在模型更改时无意中暴露数据。
指定嵌套序列化:默认的 ModelSerializer 使用主键进行关联,但你也可以使用 depth 选项轻松生成嵌套表示 (自关联)
显式指定字段:你可以将额外的字段添加到ModelSerializer ,或者通过在类上声明字段来覆盖默认字段,就像你 对 Serializer 类所做的那样。
指定只读字段:你可能希望将多个字段指定为只读。不要显式给每个字段添加 read_only = True 属性,你可以使 用快捷方式 Meta 选项 read_only_fields 。
其他关键字参数:还有一个快捷方式允许你使用 extra_kwargs 选项在字段上指定任意附加关键字参数。与 read_only_fields 的情况一样,这意味着你不需要在序列化类中显式声明该字段。
关系字段:序列化模型实例时,可以选择多种不同的方式来表示关系。 ModelSerializer 的默认表示是使用相 关实例的主键。
自定义字段映射:ModelSerializer 类还公开了一个可以覆盖的 API,以便在实例化序列化对象时更改序列化对象的 字段。
更多序列化器
除了上面两个序列化器外,还有集成度更高或更具个性的序列化器:HyperlinkedModelSerializer、ListSerializer、BaseSerializer等等
详见官方文档。