如何使用DRF的序列化器之反序列化
驗證資料:使用序列化器進行反序列化時,需要對資料進行驗證後,才能獲取驗證成功的資料或儲存成模型類物件。
在獲取反序列化的資料前,必須呼叫is_valid()方法進行驗證,驗證成功返回True,否則返回False。is_valid()方法還可以在驗證失敗時丟擲異常serializers.ValidationError,可以通過傳遞raise_exception=True引數開啟,REST framework接收到此異常,會向前端返回HTTP 400 Bad Request響應。
# Return a 400 response if the data was invalid. serializer.is_valid(raise_exception=True)
驗證成功,可以通過序列化器物件的validated_data屬性獲取資料。serializer.validated_data為OrderedDict物件 如OrderedDict([('btitle', 'python進階')])
通過構造序列化器物件,並將要反序列化的資料傳遞給data構造引數,進而進行驗證
from booktest.serializers import BookInfoSerializer data = {'bpub_date': 2008.12.29} serializer = BookInfoSerializer(data=data) serializer.is_valid() # 返回False serializer.errors # {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]} serializer.validated_data # {} data = {'btitle': 'python'} serializer = BookInfoSerializer(data=data) serializer.is_valid() # True serializer.errors # {} serializer.validated_data # OrderedDict([('btitle', 'python')])
在定義序列化器時,指明每個欄位的序列化型別和選項引數,本身就是一種驗證行為。
序列化器還提供了驗證函式用來自定義驗證:
def validate_屬性(self, value): 用來針對單個欄位進行驗證
class BookInfoSerializer(serializers.Serializer): """圖書資料序列化器""" ... def validate_btitle(self, value): if 'django' not in value.lower(): raise serializers.ValidationError("圖書不是關於Django的") return value
def validate(self, attrs):用來同時對多個欄位進行驗證
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def validate(self, attrs):
bread = attrs['bread']
bcomment = attrs['bcomment']
if bread < bcomment:
raise serializers.ValidationError('閱讀量小於評論量')
return attrs
驗證函式一定要將驗證後的資料return!
validators選項,在欄位中新增validators選項引數,可以補充驗證行為
def about_django(value):
if 'django' not in value.lower():
raise serializers.ValidationError("圖書不是關於Django的")
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
bpub_date = serializers.DateField(label='釋出日期', required=False)
儲存資料:如果在驗證成功後,想要基於validated_data完成資料物件的建立及儲存到資料庫,可以通過實現create()和update()兩個方法來實現。
在序列化器類中新增creat和update方法
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def create(self, validated_data):
"""新建"""
return BookInfo.objects.create(**validated_data)
def update(self, instance, validated_data):
"""更新,instance為要更新的物件例項"""
instance.btitle = validated_data.get('btitle', instance.btitle)
instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
instance.bread = validated_data.get('bread', instance.bread)
instance.bcomment = validated_data.get('bcomment', instance.bcomment)
instance.save()
return instance
實現了上述兩個方法後,在反序列化資料的時候,就可以通過save()方法返回一個數據物件例項了
book = serializer.save()
如果建立序列化器物件的時候,沒有傳遞instance例項,則呼叫save()方法的時候,create()被呼叫,相反,如果傳遞了instance例項,則呼叫save()方法的時候,update()被呼叫。不需要手動呼叫validated_date。
from db.serializers import BookInfoSerializer
data = {'btitle': 'python進階'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: python進階>
from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': 'python核心程式設計'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: python核心程式設計>
book.btitle # 'python核心程式設計'
兩點說明:
1) 在對序列化器進行save()儲存時,可以額外傳遞資料,這些資料可以在create()和update()中的validated_data引數獲取到。
serializer.save(owner=request.user)
2)預設序列化器必須傳遞所有required的欄位,否則會丟擲驗證異常。但是我們可以使用partial引數來允許部分欄位更新,建立serializer物件時,傳入partial引數,則所有欄位的required選項失效。
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'tx'}, partial=True)
反序列化幫我們封裝了將字典轉換為物件的過程。
# 建立物件
serializer = BookInfoSerializer(data=data)
serializer.save()
# 更新物件
serializer = BookInfoSerializer(book, data=data)
serializer.save()