zoukankan      html  css  js  c++  java
  • 反序列化

    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 = {'bpub_date': 123}
    serializer = BookInfoSerializer(data=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 = {'btitle': 'python'}
    serializer = BookInfoSerializer(data=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)


    如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:

    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 = {'btitle': 'python'}
    serializer = BookInfoSerializer(data=data)
    serializer.is_valid()  # False   
    serializer.errors
    #  {'btitle': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
    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 = {'btitle': 'python'}
    serializer = BookInfoSerializer(data=data)
    serializer.is_valid()  # False   
    serializer.errors
    #  {'btitle': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}


    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 = {'btitle': 'about django', 'bread': 10, 'bcomment': 20}
    s = BookInfoSerializer(data=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')
                )
            ]

    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 = {'btitle': '封神演义'}
    serializer = BookInfoSerializer(data=data)
    serializer.is_valid()  # True
    serializer.save()  # <BookInfo: 封神演义>
    
    from db.models import BookInfo
    book = BookInfo.objects.get(id=2)
    data = {'btitle': '倚天剑'}
    serializer = BookInfoSerializer(book, data=data)
    serializer.is_valid()  # True
    serializer.save()  # <BookInfo: 倚天剑>
    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={'content': u'foo bar'}, partial=True)
  • 相关阅读:
    HDU 4348 To the moon(可持久化线段树)
    HDU 5875 Function 大连网络赛 线段树
    HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
    HDU 5876 大连网络赛 Sparse Graph
    HDU 5701 中位数计数 百度之星初赛
    CodeForces 708B Recover the String
    Java实现 蓝桥杯 算法提高 套正方形(暴力)
    ASP.NET生成验证码
    ASP.NET生成验证码
    ASP.NET生成验证码
  • 原文地址:https://www.cnblogs.com/py-web/p/10985562.html
Copyright © 2011-2022 走看看