REST framework中的序列化類與Django的Form
和ModelForm
類很是類似。咱們提供了一個Serializer
類,它提供了一種強大的通用方法來控制響應的輸出,以及一個ModelSerializer
類,它爲建立處理模型實例和查詢集的序列化提供了有效的快捷方式。git
序列化器容許把像查詢集和模型實例這樣的複雜數據轉換爲能夠輕鬆渲染成JSON
,XML
或其餘內容類型的原生Python類型。序列化器還提供反序列化,在驗證傳入的數據以後容許解析數據轉換回複雜類型。不只僅有序列化功能,更提供了數據驗證的功能(與django中的form相似)github
讓咱們從建立一個簡單的對象開始,咱們可使用下面的例子:django
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
對象相應的數據。json
聲明一個序列化器看起來很是像聲明一個form:api
from rest_framework import serializers class CommentSerializer(serializers.Serializer): email = serializers.EmailField() content = serializers.CharField(max_length=200) created = serializers.DateTimeField()
# 序列化(Python原生的數據類型dict) serializer = CommentSerializer(comment) serializer.data # {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
#轉化爲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"}'
# 反序列化 from django.utils.six import BytesIO from rest_framework.parsers import JSONParser stream = BytesIO(json) data = JSONParser().parse(stream)
若是咱們但願可以返回基於驗證數據的完整對象實例,咱們須要實現其中一個或所有實現.create()
和update()
方法。例如:ide
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) # return Comment.objects.create(**validated_data) # model對象 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() model對象 return instance
ps:.create()
和.update()
方法都是可選的。你能夠根據你序列化器類的用例不實現、實現它們之一或都實現。post
如今當咱們反序列化數據的時候,基於驗證過的數據咱們能夠調用.save()
方法返回一個對象實例。網站
comment = serializer.save()
調用.save()
方法將建立新實例或者更新現有實例,具體取決於實例化序列化器類的時候是否傳遞了現有實例:ui
# .save() will create a new instance. serializer = CommentSerializer(data=data) # .save() will update the existing `comment` instance. serializer = CommentSerializer(comment, data=data)
默認狀況下,序列化程序必須爲全部必填字段傳遞值,不然會引起驗證錯誤。你可使用partial
參數以容許部分更新spa
# .save() will update the existing `comment` instance. serializer = CommentSerializer(comment, data=data,partial=True)
反序列化數據的時候,你始終須要先調用is_valid()
方法,而後再嘗試去訪問通過驗證的數據或保存對象實例。若是發生任何驗證錯誤,.errors
屬性將包含表示生成的錯誤消息的字典。例如:
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
鍵可能存在,它將列出任何通常驗證錯誤信息。non_field_errors
的名稱能夠經過REST framework設置中的NON_FIELD_ERRORS_KEY
來自定義。 當對對象列表進行序列化時,返回的錯誤是每一個反序列化項的字典列表。
拋出無效數據的異常
.is_valid()
方法使用可選的raise_exception
標誌,若是存在驗證錯誤將會拋出一個serializers.ValidationError
異常。
這些異常由REST framework提供的默認異常處理程序自動處理,默認狀況下將返回HTTP 400 Bad Request
響應。
# 若是數據無效就返回400響應 serializer.is_valid(raise_exception=True)
你能夠經過向你的Serializer
子類中添加.validate_<field_name>
方法來指定自定義字段級別的驗證。這些相似於Django表單中的.clean_<field_name>
方法。
這些方法採用單個參數,即須要驗證的字段值。
你的validate_<field_name>
方法應該返回一個驗證過的數據或者拋出一個serializers.ValidationError
異常。例如:
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
注意: 若是你在序列化器中聲明<field_name>
的時候帶有required=False
參數,字段不被包含的時候這個驗證步驟就不會執行。
要執行須要訪問多個字段的任何其餘驗證,請添加一個.validate()
方法到你的Serializer
子類中。這個方法採用字段值字典的單個參數,若是須要應該拋出一個 ValidationError
異常,或者知識返回通過驗證的值。例如:
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 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') class GameRecord(serializers.Serializer): score = IntegerField(validators=[multiple_of_ten])
序列化器類還能夠包括應用於一組字段數據的可重用的驗證器。validators給咱們提供了不少很好的功能:UniqueValidator,UniqueTogetherValidator等。
這些驗證器要在內部的Meta
類中聲明,以下所示:
UniqueTogetherValidator:(表示聯合惟一)
class EventSerializer(serializers.Serializer): name = serializers.CharField() room_number = serializers.IntegerField(choices=[101, 102, 103, 201]) date = serializers.DateField() class Meta: # 每間屋子天天只能有1個活動。 validators = UniqueTogetherValidator( queryset=Event.objects.all(), fields=['room_number', 'date'] )
UniqueValidator:
username = serializers.CharField( max_length=11, min_length=11, validators=[UniqueValidator(queryset=UserProfile.objects.all()) )
更多信息請參閱 validators文檔。
它爲建立用於處理模型實例和查詢集的序列化程序提供了有用的快捷實現方式。自動建立一個Serializer類,字段與model的字段一一對應。
ModelSerializer類與常規Serializer類相同,不一樣之處在於:
聲明ModelSerializer以下,在Meta中設置fields字段,系統會自動進行映射成序列化字段,省去每一個字段再寫一個field。
class CourseSerializer(serializers.ModelSerializer): """ 課程序列化 """class Meta: model = models.Course # 字段顯示 fields = ['id','title','level'] # # fields = '__all__': 表示全部字段 # exclude = ('add_time',): 除去指定的某些字段 # 只讀字段 ---多個字段只讀,咱們能夠這樣設置,不用每一個字段都設置read_only=True read_only_fields=(「field_name」,) # editable=False、AutoField 默認只讀,不用添加
任何關係(如模型上的外鍵)都將映射到PrimaryKeyRelatedField(但得到外鍵類別的id)。除非在序列化關係文檔中指定,不然默認不包括反向關係。
class CourseDetailSerializer(serializers.ModelSerializer): """ 課程詳細序列化 """ # choice level = serializers.CharField(source='course.get_level_display') # one2one/fk # 外鍵方式一 須要單個信息 title = serializers.ReadOnlyField(source='course.title') # 外鍵方式二 須要更多信息 course=CourseSerializer(many=True) # m2m 方法一:使用SerializerMethodField(method_name=None)方法,but該方法爲readonly字段。 #---當不指定method_name ,默認爲get_field_name, recommends = serializers.SerializerMethodField() chapter = serializers.SerializerMethodField() class Meta: model = models.CourseDetail fields = ['course','title','img','level','slogon','why','recommends','chapter'] # 外鍵方式三 depth 表示應該遍歷的關聯深度 # depth = 1 另外訪問時顯示外鍵字段的全部信息,可是隻讀的,不可編輯,即新建時不能傳值 def get_recommends(self,obj): # 獲取推薦的全部課程 queryset = obj.recommend_courses.all() return [{'id':row.id,'title':row.title} for row in queryset] def get_chapter(self,obj): # 獲取推薦的全部課程 queryset = obj.course.chapter_set.all() return [{'id':row.id,'name':row.name} for row in queryset]
def validate(self, attrs): del attrs["code"] return attrs
class UserSerializer(serializers.ModelSerializer): days_since_joined = serializers.SerializerMethodField() class Meta: model = User # 方法寫法:get_ + 字段 def get_days_since_joined(self, obj): # obj指這個model的對象 return (now() - obj.date_joined).days