Serializers把querysets和model instances这些复杂的数据结构转化为native Python 以便于以json,xml或其它内容类型的形式render出去。
- 类似于Django的 Form 和ModelForm
- Serializer和ModelSerializer
序列化对象
from datetime import datetime
classComment(object):def __init__(self, email, content, created=None):self.email = email
self.content = content
self.created = created or datetime.now()
from rest_framework import serializers
classCommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
comment =Comment(email='leila@example.com', content='foo bar')
serializer =CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
把数据转化为json格式
from rest_framework.renderers importJSONRenderer
json =JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
反序列化对象
把json数据转化为本地数据类型,也就是Django rest framework可以使用的数据类型
from django.utils.six importBytesIOfrom rest_framework.parsers importJSONParser
stream =BytesIO(json)
data =JSONParser().parse(stream)
让后进一步把这些数据绑定到serializers上面,serializer = CommentSerializer(data=data)之后使用serializer.is_valid()验证传进来的数据(上段代码的data是否符合CommentSerializer的格式,这里可以写一个try-exception.现在可以在serializer.validated_data找到传进来的数据。
在访问validated data或板寸validated data之前一定要检查serializer.is_valid()是否为true。如果为false的话错误信息包含在serializer.errors里。
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)}
保存instances
我们应该实现基本的create和update方法,把数据写入数据库
def create(self, validated_data): returnComment.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
如果不需要写入数据库,可以直接放回数据就好了
classCommentSerializer(serializers.Serializer): email = serializers.EmailField() content = serializers.CharField(max_length=200) created = serializers.DateTimeField()def create(self, validated_data):returnComment(**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
在命令行中的编写如下:
创建一个新的对象
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)} comment = serializer.save()
更新已经存在的comment实例
serializer =CommentSerializer(comment, 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)} comment = serializer.save()
在save的时候添加其它内容比如
serializer.save(owner=request.user)
owner数据被绑定在serializer.validated_data对象上,当create或update的时候就会被添加进数据库。
直接重写save()方法
有时候并不需要保存或则返回数据,这个时候save()方法就需要重写。比如执行发送邮件的任务。
classContactForm(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_date属性。
验证
serializer =CommentSerializer(data={'email':'foobar','content':'baz'}) serializer.is_valid()# False serializer.errors # {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}
non_field_errors关键字有可能出现,可以在REST framework 框架的设置文件里面设置NON_FIELD_ERRORS_KEY。
is_valid()有默认的异常处理机制,raise_exception标志默认为true,框架自动帮你抛异常(serializers.ValidationError)。
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
自定义验证
类似于Django表单的clean_<fieldname>方法,你可以添加validate<field_name>方法到你的Serializer子类里面。这个方法只接受要验证的数据这一个对象。抛出的异常也是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
注意:如果你不希望这个验证方法被使用,你可以在serializer上声明required=False,那么如果这个field没有包括进来这个验证步骤就不会起作用。(这里有点不清晰)
对象级验证
如果你的验证需要访问多个fileds,你可以添加serializer的子类validate().这个方法接收一个字典参数,你需要使用的多个fileds应该包含在这个字典参数里面。报错类型为serializers.ValidationError
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 the start is before the stop. """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'])