反序列化的基本使用,is_valid()验证 validators验证器

本文介绍了反序列化时如何使用`is_valid()`进行数据验证,以及REST framework中提供的验证方式,包括`validate_fieldname`、`validate`方法和`validators`选项参数。此外,还探讨了`UniqueValidator`和`UniqueTogetherValidator`用于实现字段唯一性的验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

反序列化使用

  • 验证数据
  • 保存
验证 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
{}
>>>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值