• 04-序列化器Serializer


    Serializer定义

    序列化(Serializer)在计算机科学的资料处理中, 是指将数据结构或物件状态转换成可取用格式(例如存成档案、存于缓存、或经由网络中传送), 以留待后续在相同或另一台计算机环境中, 能恢复原来状态的过程。依照序列化格式重新获取字节的结果时, 可以利用他来产生与原始物件相同语义的副本。对于许多物件, 像是使用大量参考的复杂物件, 这种序列化重建的过程并不容易。面向对象中物件序列化, 并不概括之前原始物件所关联的函式。这种过程也称为物件编组(marshalling)。从一系列字节提取数据结构的反向操作, 是反序列化(也称为解编组, deserialization, unmarshalling)

    序列化在计算机科学中通常有如下定义:

    在数据存储与传送的部分是指将一个对象存储至一个储存媒介, 例如档案或记忆体缓冲等, 或者通过网络传送资料时进行编码的过程, 可以是字节或XML等格式。而字节的或是XML编码格式可以还原完全相同的对象。这程序被应用不同应用程序之间传送对象, 以及服务器将对象存储到档案或数据库。相反的过程又称之为反序列化

    简而言之, 可以将序列化理解为:

    将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等), 例如将Django中的模型类对象转换成JSON字符串, 这个转换过程称之为序列化

    反之, 将其他格式(字典、JSON、XML等)转换为程序中的数据, 例如将JSON字符串转换成Django中的模型类对象, 这个过程我们称之为反序列化

    DRF框架之序列化组件

    Serializer(偏底层)
    ModelSerializer(重点)
    ListModelSerializer(辅助群改)

    序列化器的基本使用

    1. 在app中创建seralizers.py文件

    2. 定义序列化器类(字段名必须和模型中的字段保存一致, 否则会出错)

    Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer

    class BookInfoSerializer(serializers.Serializer):
        id = serializers.IntegerField(label='id', read_only=True)
        name = serializers.CharField(max_length=20, label='名称')
        pub_date = serializers.DateField(label='发布日期')
        readcount = serializers.IntegerField(default=0, label='阅读量')
        commentcount = serializers.IntegerField(default=0, label='评论量')
        is_delete = serializers.BooleanField(default=False, label='逻辑删除')

    # 序列化提供给前台的字段个数由后台决定, 可以少提供, 但是提供的数据库对应的字段, 名字一定要与数据库字段相同

    字段与选项

    常用字段类型

    字段字段构造方式
    BooleanField BooleanField()
    NullBooleanField NullBooleanField()
    CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
    EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
    RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
    SlugField SlugField(maxlength=50, min_length=None, allow_blank=False)
    正则字段,验证正则模式 [a-zA-Z0-9-]+
    URLField URLField(max_length=200, min_length=None, allow_blank=False)
    UUIDField UUIDField(format='hex_verbose')
    format:
    1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
    2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a"
    3)'int' - 如: "123456789012312313134124512351145145114"
    4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
    IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
    IntegerField IntegerField(max_value=None, min_value=None)
    FloatField FloatField(max_value=None, min_value=None)
    DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
    max_digits: 最多位数
    decimal_palces: 小数点位置
    DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
    DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
    TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
    DurationField DurationField()
    ChoiceField ChoiceField(choices)
    choices与Django的用法相同
    MultipleChoiceField MultipleChoiceField(choices)
    FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ListField ListField(child=<a_field_instance>, min_length=None, max_length=None)
    DictField DictField(child=<a_field_instance>)

     选项参数

    参数名称作用
    max_length 最大长度
    min_lenght 最小长度
    allow_blank 是否允许为空
    trim_whitespace 是否截断空白字符
    max_value 最小值
    min_value 最大值

    通用参数

    参数名称说明
    read_only 表明该字段仅用于序列化输出,默认False
    write_only 表明该字段仅用于反序列化输入,默认False
    required 表明该字段在反序列化时必须输入,默认True
    default 反序列化时使用的默认值
    allow_null 表明该字段是否允许传入None,默认False
    validators 该字段使用的验证器
    error_messages 包含错误编号与错误信息的字典
    label 用于HTML展示API页面时,显示的字段名称
    help_text 用于HTML展示API页面时,显示的字段帮助提示信息

    创建Serializer对象

    Serializer的构造方法是

    Serializer(instance=None, data=empty, **kwargs)

    1)用于序列化时,将模型类对象传入instance参数

    2)用于反序列化时,将要被反序列化的数据传入data参数

    3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据

    序列化

    注意: 使用序列化器对象时, 需要传入待序列化的对象, 返回的是序列化器对象, 并不能作为数据返回(会报错)

    将序列化器数据返回可以调用序列化器的data属性返回。如果返回的是多个模型对象, 那么需要在使用序列化器的时候传入参数many=True

    基本使用

    from booktest.serializer import BookInfoSerializer, HeroInfoSerializer
    from booktest.models import BookInfo, PeopleInfo
    
    """ 1. 序列化器, 序列化单个书籍对象 """
    # 1. 获取书籍对象
    book = BookInfo.objects.get(id=1)
    
    # 2. 创建序列化器, instance: 表示要序列化的对象
    serializer = BookInfoSerializer(instance=book)
    
    # 3. 转换数据
    print(serializer.data)
    
    """ 2. 序列化器, 序列化列表书籍对象 """
    # 1. 获取书籍对象
    book = BookInfo.objects.all()
    
    # 2. 创建序列化器, instance: 表示要序列化的对象, many=True表示序列化多个对象
    serializer = BookInfoSerializer(instance=book, many=True)
    
    # 3. 转换数据
    print(serializer.data)

    关联对象嵌套序列化

    如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。

    PrimaryKeyRelatedField

    此字段将被序列化为关联对象的主键。

    book = serializers.PrimaryKeyRelatedField(read_only=True)

    注意: 指明字段时需要包含read_only=True或者queryset参数, 否则会报错

    包含read_only=True参数时,该字段将不能用作反序列化使用

    book = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())

    StringRelatedField

    PrimaryKeyRelatedField字段只会返回关联对象的主键id, 如果需要返回name等信息的时候

    而StringRelatedField字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)

    book = serializers.StringRelatedField(read_only=True)

    使用关联对象的序列化器

    book = BookInfoSerializer()

    使用many参数

    如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数即可。

    peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)

    反序列化

    反序列化基本使用

    使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

    在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

    验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。

    验证成功,可以通过序列化器对象的validated_data属性获取数据。

    在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

    通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证

    # 1. 获取前台传入的数据
    request_data = request.data
    
    # 2. 数据类型合法, 但数据内容不一定合法, 需要校验数据, 校验(参与反序列化)的数据需要赋值给data
    book_serializer = serializers.UserDeSerializer(data = request_data)
    
    # 3. 使用序列化对象调用is_valid()完成校验
    book_serializer.is_valid()
    
    # 4. 校验失败的信息都会被缓存在序列化对象.errors里面
    book_serializer.errors
    
    # 5. 校验成功, 使用save()方法将数据保存
    book_serializer.save()

    is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。

    # 1. 准备数据
    book_dict = {
        "name": "求魔",
        "pub_date": "2016-09-18",
        "readcount": 10,
        "commentcount": 5
    }
    
    # 2. 创建序列化器, 校验
    serializer = BookInfoSerializer(data=book_dict)
    serializer.is_valid(raise_exception=True)  # 校验不通过,报错
    
    # 3. 输出
    print(serializer.data)

    字段校验

    1. 字段内定义的参数进行校验

    name = serializers.CharField(
            max_length=64,
            min_length=3,
            error_messages={
                'max_length': '名称过长',
                'min_length': '名称过短',
            }
        )
    phone = serializers.CharField(required=False)

    max_length: 最长长度

    min_length: 最段长度

    error_messages: 自定义异常

    requried: 是否必传

    2. 局部校验钩子: validate_要校验的字段名(self, 当前要校验字段的值)

    # 校验规则: 校验通过返回原值, 校验失败, 抛出异常
    def validate_name(self, value):
        # print('value', value)
        if 'j' in value.lower():
            raise exceptions.ValidationError({'name': '名字非法'})
    
        return value

    3. 全局校验钩子: validate(self, 系统与局部钩子校验通过的所有数据)

    def validate(self, attrs):
        # print('attrs', attrs)
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')
        if pwd != re_pwd:
            raise exceptions.ValidationError({'pwd': '两次密码不一致'})
    
        return attrs

    4. 自定义校验规则

    def check_pub_date(value):
        if value.year < 2018:
            raise serializers.ValidationError('书籍的年份需要大于2018年')
    
        return value
    
    class BookInfoSerializer(serializers.Serializer):
        pub_date = serializers.DateField(label='发布日期', validators=[check_pub_date])

    保存数据

    如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个方法来实现。

    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参数获取到

    # request.user是django中记录登录用户的模型类对象
    serializer.save(owner=request.user)

    2) 默认序列化器必须传递所有required的字段, 否则会抛出异常。但是可以使用partial参数来允许部分字段更新

    serializer = CommentSerializer(comment, data={'content': u"foo bar"}, partial=True)
  • 相关阅读:
    linux终端发送邮件
    ubuntu交换Caps 和 ESC
    pycharm快捷键
    python catch socket timeout
    pgsql restart
    python re.sub
    文件写入与缓存
    HTTP协议再分析
    leetcode-45
    Java的锁
  • 原文地址:https://www.cnblogs.com/featherwit/p/13496339.html
Copyright © 2020-2023  润新知