反序列化的基本使用,is_valid()驗證 validators驗證器

反序列化使用

  • 驗證數據

  • 保存

驗證 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
{}
>>>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章