序列化器
允许将复杂的(如querysets或者模型实例等)数据转换到python原生的数据类型,转换成原生python数据类型之后,就可以方便的渲染成json或者是其它格式的数据。
序列化器
也提供了反序列化的功能,可以把解析后的数据转换回复杂类型(数据必须先验证)。
REST framework序列化器
的工作与Django的Form和ModelForm类非常相似。我们提供了一个序列化类,它提供了功能强大的通用方法来控制响应输出。还提供了模型序列化器
,它为创建用于处理模型实例
和查询集的
序列化器
提供了有用的快捷方式。
一个简单的对象
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='[email protected]', 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()
from rest_framework.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
json
# b'{"email":"[email protected]","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
先得到一个字典数据
import io
from rest_framework.parsers import JSONParser
import json as Json
# stream = io.BytesIO(json)
# data = JSONParser().parse(stream)
# 感觉用原生的json模块比较方便
data = Json.loads(json)
用字典数据构造序列化器
serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': '[email protected]', '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模型对应,需要保证这些方法能把对象存到数据库中。
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
之后就可以把通过校验的序列化数据返回对应的对象实例了
comment = serializer.save()
当我们调用.save方法时,如果.instance不存在则调用.create方法,如果.instance存在则调用.update方法。
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
有时候可能需要在view代码中给.save方法注入一些参数,如当前用户。
serializer.save(owner=request.user)
所有的关键字参数将包含在.create()或.update()方法的 validtate_data参数中。
有些时候.create()和.update()方法可能没有意义,比如在联系表单中我们不需要创建新实例,而是要发送邮件或其它消息。
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)
我们在.save方法中直访问了.validated_data属性
反序列化时,在范围 validated_data属性或调用save()方法前一定会先调用 is_valid()方法。
如果有也现任何校验错误,.error属性将包含错误信息的字典
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.']}
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
在序列化器的子类中,可以通过添加 .validate_
方法给 field_name 字段自定义校验方法
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
如果在声明
字段时指定了 required=False,如果该字段不在数据中,将不会执行校验步骤。
校验时可能需要用到多个字段,这时可以重载 .validate()方法
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])
...
当给序列化器的instance参数传递一个实例对象或者查询集合时,序列化器将产生一个.instance的变量,如果没有传递,.instance属性将为None
Serializer(data = {xxxx}) # .initial_data可以访问
Serializer() # .initial_data属性不存在
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True)
序列化器字段本身就是一个序列化器,可以表示嵌套关系。
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值
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False) # May be an anonymous user.
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
嵌套的是对象列表
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() 和 .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
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
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
序列化器中调用 manager 的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']
)
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'}
# ]
您可以在实例化序列化程序时通过传递上下文参数来提供任意其他上下文。
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'}
之后就可以在任何地方引用 self.context属性了。
序列化器常与Django的模型类有紧密的映射关系。
ModelSerializer类提供了便捷方法来自动创建与模型类相对应的字段。
ModelSerializer类和Serializer一样,除了:
声明ModelSerializer类如下:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
默认的,所有的模型字段都会映射为对应的序列化类的字段
任何引用关系,如外键将会映射为PrimaryKeyRelatedField.
默认情况下不包括反向关系,除非按照序列化器关系文档中的指定明确包含反向关系。
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
# 包含所有
# fields = '__all__'
指定不包含的字段
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
exclude = ['users']
默认的,使用主键来代表引用关系,也可以通过depth选项来生成嵌套关系
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
depth = 1
也可以重写或添加一些额外的字段
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表示只读字段,也可以通过 Meta 选项的 read_only_fields指定
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
read_only_fields = ['account_name']
在模型类中指定 editable=False,自动生成的字段默认也会被设置成 只读。
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['email', 'username', 'password']
# 除指定read_only外还可以指定其它参数,如queryset等
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默认使用主键来表示被引用的实力。
有关完整的详细信息,请参见序列化程序关系文档。
序列化器字段处理原始值和内部数据类型之间的转换。 它们还处理验证输入值,以及从其父对象检索和设置值。
每个序列化器字段类构造函数都至少接受这些参数。 某些Field类采用其他特定于字段的参数,但应始终接受以下内容:
read_only
只读字段包含在API输出中,但在创建或更新操作期间不应包含在输入中。 错误地包含在序列化器输入中的所有“只读”字段都将被忽略。
默认: False
write_only
中接收输入,不会输出
默认: False
required
是否是必须的
默认: False
allow_null
默认: False
source
将用于填充字段的属性的名称。
validators
验证器
error_messages
initial