反序列化使用
- 验证数据
- 保存
验证 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构造参数,进而进行验证
#### 错误
```python
>>> 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
{}
>>>