反序列化使用
-
驗證數據
-
保存
驗證 is_valid()
使用序列化器進行反序列化時,需要對數據進行驗證後,才能獲取驗證成功的數據或保存成模型類對象。
在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,否則返回False。
驗證失敗,可以通過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。
驗證成功,可以通過序列化器對象的validated_data屬性獲取數據。
在定義序列化器時,指明每個字段的序列化類型和選項參數,本身就是一種驗證行爲。
如我們前面定義過的BookInfoSerializer
class BookInfoSerializer(serializers.Serializer):
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
name = serializers.CharField(label='名稱', max_length=20)
pub_date = serializers.DateField(label='發佈日期', required=False)
readcount = serializers.IntegerField(label='閱讀量', required=False)
commentcount = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
通過構造序列化器對象,並將要反序列化的數據傳遞給data構造參數,進而進行驗證
錯誤
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':123}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid()
False
>>> serializer.errors
{'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')], 'name': [ErrorDetail(string='This field is required.', code='required')]}
>>> serializer.validated_data
{}
正確
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'python高級'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.errors
{}
>>> serializer.validated_data
OrderedDict([('name', 'python高級'), ('pub_date', datetime.date(2010, 1, 1))])
is_valid()
方法還可以在驗證失敗時拋出異常 serializers.ValidationError
,可以通過傳遞raise_exception=True
參數開啓,REST framework
接收到此異常,會向前端返回 HTTP 400 Bad Request
響應。
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':123}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/yangjianmei/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/rest_framework/serializers.py", line 244, in is_valid
raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')], 'name': [ErrorDetail(string='This field is required.', code='required')]}
>>> serializer.errors
{'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')], 'name': [ErrorDetail(string='This field is required.', code='required')]}
>>> serializer.validated_data
{}
如果覺得這些還不夠,需要再補充定義驗證行爲,可以使用以下三種方法:
-
validate_fieldname
-
validate
-
validators
<其他測試>
validate_<field_name>
對 <field_name>
字段進行驗證,如
class BookInfoSerializer(serializers.Serializer):
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
name = serializers.CharField(label='名稱', max_length=20)
pub_date = serializers.DateField(label='發佈日期', required=False)
readcount = serializers.IntegerField(label='閱讀量', required=False)
commentcount = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
def validate_readcount(self,value):
if value < 0:
raise serializers.ValidationError('閱讀數量不能爲負數')
return value
測試
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'python高級','readcount':-11}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/yangjianmei/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/rest_framework/serializers.py", line 244, in is_valid
raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'readcount': [ErrorDetail(string='閱讀數量不能爲負數', code='invalid')]}
>>> serializer.errors
{'readcount': [ErrorDetail(string='閱讀數量不能爲負數', code='invalid')]}
>>> serializer.validated_data
{}
validate
在序列化器中需要同時對多個字段進行比較驗證時,可以定義validate方法來驗證,如
class BookInfoSerializer(serializers.Serializer):
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
name = serializers.CharField(label='名稱', max_length=20)
pub_date = serializers.DateField(label='發佈日期', required=False)
readcount = serializers.IntegerField(label='閱讀量', required=False)
commentcount = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
def validate(self, attrs):
readcount = attrs['readcount']
commentcount = attrs['commentcount']
if commentcount > readcount:
raise serializers.ValidationError('評論量不能大於閱讀量')
return attrs
測試
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'python高級','readcount':11,'commentcount':22}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/yangjianmei/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/rest_framework/serializers.py", line 244, in is_valid
raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'non_field_errors': [ErrorDetail(string='評論量不能大於閱讀量', code='invalid')]}
>>> serializer.errors
{'non_field_errors': [ErrorDetail(string='評論量不能大於閱讀量', code='invalid')]}
>>> serializer.validated_data
{}
validators
在字段中添加validators選項參數,也可以補充驗證行爲,如
class BookInfoSerializer(serializers.Serializer):
def custom_validate(value):
raise serializers.ValidationError('我就是來搗亂的')
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
name = serializers.CharField(label='名稱', max_length=20,validators=[custom_validate])
pub_date = serializers.DateField(label='發佈日期', required=False)
readcount = serializers.IntegerField(label='閱讀量', required=False)
commentcount = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
測試:
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'python高級'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/yangjianmei/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/rest_framework/serializers.py", line 244, in is_valid
raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'name': [ErrorDetail(string='我就是來搗亂的', code='invalid')]}
>>> serializer.errors
{'name': [ErrorDetail(string='我就是來搗亂的', code='invalid')]}
>>> serializer.validated_data
{}
REST framework提供的validators
驗證器
注意: 在進行唯一性校驗時,如果提交一本已經存在的書籍,就不用實現對應的create方法;
如果第一次提交一本不存在的書籍會報錯,需要按照筆記中的操作
UniqueValidator單字段唯一,如
from rest_framework.validators import UniqueValidator
class BookInfoSerializer(serializers.Serializer):
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
# name = serializers.CharField(label='名稱', max_length=20,validators=[custom_validate])
pub_date = serializers.DateField(label='發佈日期', required=False)
readcount = serializers.IntegerField(label='閱讀量', required=False)
commentcount = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
#這裏
name = serializers.CharField(max_length=20,validators=[UniqueValidator(queryset=BookInfo.objects.all())])
def create(self, validated_data):
return BookInfo.objects.create(**validated_data)
測試:第一次數據保存
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'python高級'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
True
>>> serializer.errors
{}
>>> serializer.validated_data
OrderedDict([('pub_date', datetime.date(2010, 1, 1)), ('name', 'python高級')])
>>> serializer.save()
>
<BookInfo: python高級>
第二次操作
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'python高級'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/yangjianmei/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/rest_framework/serializers.py", line 244, in is_valid
raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'name': [ErrorDetail(string='This field must be unique.', code='unique')]}
>>> serializer.errors
{'name': [ErrorDetail(string='This field must be unique.', code='unique')]}
>>> serializer.validated_data
{}
>>>
UniqueTogetherValidation聯合唯一,如
from rest_framework.validators import UniqueTogetherValidator
class BookInfoSerializer(serializers.Serializer):
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
name = serializers.CharField(label='名稱', max_length=20)
pub_date = serializers.DateField(label='發佈日期', required=False)
readcount = serializers.IntegerField(label='閱讀量', required=False)
commentcount = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
classMeta:
validators = [
UniqueTogetherValidator(
queryset=BookInfo.objects.all(),
fields= ('name','pub_date')
)
]
def create(self, validated_data):
return BookInfo.objects.create(**validated_data)
測試:第一次插入 data={‘pub_date’:‘2010-1-1’,‘name’:‘go語言’}
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'go語言'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
True
>>> serializer.errors
{}
>>> serializer.validated_data
OrderedDict([('name', 'go語言'), ('pub_date', datetime.date(2010, 1, 1))])
>>> serializer.save()
<BookInfo: go語言>
第二次插入
>>>
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-2-1','name':'go語言'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
True
>>> serializer.errors
{}
>>> serializer.validated_data
OrderedDict([('name', 'go語言'), ('pub_date', datetime.date(2010, 2, 1))])
>>> serializer.save()
<BookInfo: go語言>
第三次插入
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-2-1','name':'go語言'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/yangjianmei/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/rest_framework/serializers.py", line 244, in is_valid
raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'non_field_errors': [ErrorDetail(string='The fields name, pub_date must make a unique set.', code='unique')]}
>>> serializer.errors
{'non_field_errors': [ErrorDetail(string='The fields name, pub_date must make a unique set.', code='unique')]}
>>> serializer.validated_data
{}
>>>