Serializers
序列化程序允许将复杂的数据(如查询和模型实例)转换为原始python数据类型,然后可以轻松地将其呈现为json、xml或其他内容类型。在首次对输入的数据进行验证后,serializers也提供反序列化能够将解析后的数据转换回复杂的数据类型。
Declaring Serializers
首先创建一个简单的object用于示例:
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进行序列化和反序列话的Serializer
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
我们现在使用CommentSerializer对一个或一组comment进行序列化
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)}
Saving instances
如果我们希望能够返回基于验证的完整的对象实例,我们需要实现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)
呃呃呃呃呃 太慢了 记录要点吧
Passing additional attributes to .save()
在保存实例时还可以在.save()中添加字段参数
serializer.save(owner=request.user)
在某些情况下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)
(毛啊没看懂)
Validation
对数据进行反序列化,使用验证数据前需要先调用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.']}
When deserializing a list of items, errors will be returned as a list of dictionaries representing each of the deserialized items.
Raising an exception on invalid data
The .is_valid()
method takes an optional raise_exception
flag that will cause it to raise a serializers.ValidationError
exception if there are validation errors.
These exceptions are automatically dealt with by the default exception handler that REST framework provides, and will return HTTP 400 Bad Request
responses by default.
# 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
对多个字段做验证,add a method called .validate()
to your Serializer
subclass.
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
serializer的单个字段能够包含validators,
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])
Serializer classes也能包含可以复用的验证器, 能够作用于完整的字段集, 在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']
)
Partial updates
默认情况下,序列化时必须传递所有required字段的值,但是可以使用partial来部分更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True)
Dealing with nested objects
一个对象嵌套在另一个对象里, 就是一个对象是另一个对象的一个字段
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()
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()
Writable nested representations
嵌套对象的字段错误也被嵌套
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.']}
实在是太慢了