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'])