三、反序列化使用
3.1 驗證
使用序列化器進行反序列化時,需要對資料進行驗證后,才能獲取驗證成功的資料或保存成模型類物件,
在獲取反序列化的資料前,必須呼叫is_valid()方法進行驗證,驗證成功回傳True,否則回傳False,
驗證失敗,可以通過序列化器物件的errors屬性獲取錯誤資訊,回傳字典,包含了欄位和欄位的錯誤,如果是非欄位錯誤,可以通過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名,
驗證成功,可以通過序列化器物件的validated_data屬性獲取資料,
在定義序列化器時,指明每個欄位的序列化型別和選項引數,本身就是一種驗證行為,
如我們前面定義過的BookInfoSerializer
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發布日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
通過構造序列化器物件,并將要反序列化的資料傳遞給data構造引數,進而進行驗證
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/yanadoude/p/{'bpub_date': 123}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/yanadoude/p/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 = https://www.cnblogs.com/yanadoude/p/{'btitle': 'python'}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/yanadoude/p/data)
serializer.is_valid() # True
serializer.errors # {}
serializer.validated_data # OrderedDict([('btitle', 'python')])
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)
如果覺得這些還不夠,需要再補充定義驗證行為,可以使用以下三種方法:
3.1.1)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)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
測驗:
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/yanadoude/p/{'btitle': 'python'}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/yanadoude/p/data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關于Django的', code='invalid')]}
3.1.2)validate_<field_name>
對<field_name>欄位進行驗證,如
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def validate_btitle(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("圖書不是關于Django的")
return value
測驗
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/yanadoude/p/{'btitle': 'python'}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/yanadoude/p/data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關于Django的', code='invalid')]}
3.1.3)validate
在序列化器中需要同時對多個欄位進行比較驗證時,可以定義validate方法來驗證,如
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def validate(self, attrs):
bread = attrs['bread']
bcomment = attrs['bcomment']
if bread < bcomment:
raise serializers.ValidationError('閱讀量小于評論量')
return attrs
測驗
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/yanadoude/p/{'btitle': 'about django', 'bread': 10, 'bcomment': 20}
s = BookInfoSerializer(data=https://www.cnblogs.com/yanadoude/p/data)
s.is_valid() # False
s.errors
# {'non_field_errors': [ErrorDetail(string='閱讀量小于評論量', code='invalid')]}
REST framework提供的validators:
-
UniqueValidator
單欄位唯一,如
from rest_framework.validators import UniqueValidator slug = SlugField( max_length=100, validators=[UniqueValidator(queryset=BlogPost.objects.all())] ) -
UniqueTogetherValidation
聯合唯一,如
from rest_framework.validators import UniqueTogetherValidator class ExampleSerializer(serializers.Serializer): # ... class Meta: validators = [ UniqueTogetherValidator( queryset=ToDoItem.objects.all(), fields=('list', 'position') ) ]
3.2 保存
如果在驗證成功后,想要基于validated_data完成資料物件的創建,可以通過實作create()和update()兩個方法來實作,
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def create(self, validated_data):
"""新建"""
return BookInfo(**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)
return instance
如果需要在回傳資料物件的時候,也將資料保存到資料庫中,則可以進行如下修改
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()被呼叫,
from db.serializers import BookInfoSerializer
data = https://www.cnblogs.com/yanadoude/p/{'btitle': '封神演義'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: 封神演義>
from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = https://www.cnblogs.com/yanadoude/p/{'btitle': '倚天劍'}
serializer = BookInfoSerializer(book, data=https://www.cnblogs.com/yanadoude/p/data)
serializer.is_valid() # True
serializer.save() #
book.btitle #'倚天劍'
兩點說明:
1) 在對序列化器進行save()保存時,可以額外傳遞資料,這些資料可以在create()和update()中的validated_data引數獲取到
serializer.save(owner=request.user)
2)默認序列化器必須傳遞所有required的欄位,否則會拋出驗證例外,但是我們可以使用partial引數來允許部分欄位更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data=https://www.cnblogs.com/yanadoude/p/{'content': u'foo bar'}, partial=True)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/117826.html
標籤:Python
上一篇:《自拍教程72》Python批量重命名視頻檔案,AV專家必備!
下一篇:pickle存盤和讀取資料
