zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    Linkerd 2.10(Step by Step)—将 GitOps 与 Linkerd 和 Argo CD 结合使用
    Linkerd 2.10(Step by Step)—多集群通信
    Linkerd 2.10(Step by Step)—使用 Kustomize 自定义 Linkerd 的配置
    Linkerd 2.10(Step by Step)—控制平面调试端点
    Linkerd 2.10(Step by Step)—配置超时
    Linkerd 2.10(Step by Step)—配置重试
    Linkerd 2.10(Step by Step)—配置代理并发
    本地正常运行,线上环境诡异异常原因集合
    Need to invoke method 'xxx' declared on target class 'yyy', but not found in any interface(s) of the exposed proxy type
    alpine 安装常用命令
  • 原文地址:https://www.cnblogs.com/featherwit/p/13496339.html
Copyright © 2011-2022 走看看