zoukankan      html  css  js  c++  java
  • Python(二)Marshmallow 库相关学习

    0. 前言

    • Marshmallow 是一个用于将 ORM 对象与 Python 原生数据类型之间转换的库。实现 object → dict、object → list、string → dict 和 string → list 等功能

    1. Schema

    • 实现一个 object 和 json 之间的转化需要一个 Schema 对象作为中间载体,同时实现校验的功能:
    class ImageTpl(Schema):
        value = fields.Dict(required=True, error_messages=get_field_valid_msg("图片模版值"))
        height = fields.Int(required=True, error_messages=get_field_valid_msg("图片模版高度"))
        width = fields.Int(required=True, error_messages=get_field_valid_msg("图片模版宽度"))

    2. 序列化

    • 序列化使用 dump() 或者 dumps() 方法,其中 dump() 实现 object → dict,dumps() 实现 object → string:
    from marshmallow import pprint
    
    user = User(name="Monty", email="monty@python.org")
    schema = UserSchema()
    result = schema.dump(user)
    pprint(result.data)
    # {"name": "Monty",
    #  "email": "monty@python.org",
    #  "created_at": "2014-08-17T14:54:16.049594+00:00"}
    • 序列化的结果可以通过 only 参数指定字段:
    from pprint import pprint
    
    user_data = {
        'created_at': '2014-08-11T05:26:03.869245',
        'email': u'ken@yahoo.com',
        'name': u'Ken'
    }
    schema = UserSchema()
    result = schema.load(user_data)
    pprint(result.data)
    # {'name': 'Ken',
    #  'email': 'ken@yahoo.com',
    #  'created_at': datetime.datetime(2014, 8, 11, 5, 26, 3, 869245)},

    3. 反序列化

    • 反序列化使用 load() 或者 loads() 方法,分别实现 dict → object 和 string → object。其中 dict → object 需要添加装饰器,自己实现逻辑:
    from marshmallow import Schema, fields, post_load
    
    class UserSchema(Schema):
        name = fields.Str()
        email = fields.Email()
        created_at = fields.DateTime()
    
        @post_load
        def make_user(self, data):
            return User(**data)
    
    user_data = {
        'name': 'Ronnie',
        'email': 'ronnie@stones.com'
    }
    schema = UserSchema()
    result = schema.load(user_data)
    result.data  # => <User(name='Ronnie')>

    4. Field 对象

    • Schema 对象为每个属性赋值为一个 Field 对象设定转换类型的校验参数,具体如下:
    • validate 参数:指定一个 lambda 函数或者函数,定义校验逻辑,传入函数定义了 ValidationError 的话,返回信息会记录抛出的异常:
    from marshmallow import Schema, fields, ValidationError
    
    def validate_quantity(n):
        if n < 0:
            raise ValidationError('Quantity must be greater than 0.')
        if n > 30:
            raise ValidationError('Quantity must not be greater than 30.')
    
    class ItemSchema(Schema):
        quantity = fields.Integer(validate=validate_quantity)
    
    in_data = {'quantity': 31}
    result, errors = ItemSchema().load(in_data)
    errors  # => {'quantity': ['Quantity must not be greater than 30.']}
    • required 参数:标记该字段必须传递切被校验
    • error_messages 参数:传递字典定义错误返回信息:
    def get_field_valid_msg(field_name):
        return {
            'required': '[%s] 字段必填' % field_name,
            'type': '[%s] 字段类型不合法' % field_name, # used by Unmarshaller
            'null': '[%s] 字段不能为空' % field_name,
            'validator_failed': '[%s] 字段值不合法' % field_name
        }
    • many 参数:同 fields.Nested 同用表示指定元素类型的数组类型,严格按照数据类型校验,fields.Nested 表示制定另一个 Schema 作为外键:
    ......
    'components': fields.Nested(Component, required=True, many=True,
                                        error_messages=get_field_valid_msg("组件信息")),
    ......
    • fields.List 类型:一类 Field 元素,可以指定元素类型,对于传递的非数组类型的元素,会自动包装为一个数组

    5. 验证

    • 对于 Schema 的校验有很多方式,通过上述 Field 元素的相关参数已经实现了很多对元素的校验
    • 也可以通过定义 @validates(field_name) 装饰器定义特定属性的校验函数
    • 也可以通过定义 @validate_schema() 装饰器定义 Schema 级别的校验函数:
    @validates_schema
        def validate_element_type(self, value):
    
            switch = {
                DpaVideoPackageElementType.TEXT : lambda x : x in DpaVideoPackageDataType.text_types(),
                DpaVideoPackageElementType.IMAGE : lambda x : x in DpaVideoPackageDataType.image_types(),
                DpaVideoPackageElementType.LOGO : lambda x : x in DpaVideoPackageDataType.logo_types()
            }
    
            try:
                if not switch[value['element_type']](value['data_type']):
                    raise ValidationError("组件类型和组件数据类型不匹配")
            except KeyError as e:
                raise ValidationError("组件类型不存在")
    • 对于一个 Schema,load() 和 loads 方法会在返回值中加入验证错误的信息:
    class ImageOrImageMeta(Schema):
        value = fields.String(required=True, error_messages=get_field_valid_msg("图片或图片元数据值"))
        height = fields.Int(required=True, error_messages=get_field_valid_msg("图片或图片元数据高度"))
        width = fields.Int(required=True, error_messages=get_field_valid_msg("图片或图片元数据宽度"))
    
    class ImageTpl(Schema):
        value = fields.Dict(required=True, error_messages=get_field_valid_msg("图片模版值"))
        height = fields.Int(required=True, error_messages=get_field_valid_msg("图片模版高度"))
        width = fields.Int(required=True, error_messages=get_field_valid_msg("图片模版宽度"))
    
    class TextOrTextMeta(Schema):
        value = fields.String(required=True, error_messages=get_field_valid_msg("文本或文本元数据值"))
        default_val = fields.String(error_messages=get_field_valid_msg("文本或文本元数据默认值"))
        max_length = fields.Int(required=True, error_messages=get_field_valid_msg("文本或文本元数据最大值"))
    ......
            switch = {
                DpaVideoPackageDataType.IMAGE : lambda x : ImageOrImageMeta().load(x),
                DpaVideoPackageDataType.IMAGE_META : lambda x : ImageOrImageMeta().load(x),
                DpaVideoPackageDataType.IMAGE_TPL : lambda  x : ImageTpl().load(x),
                DpaVideoPackageDataType.TEXT : lambda  x : TextOrTextMeta().load(x),
                DpaVideoPackageDataType.TEXT_META : lambda  x : TextOrTextMeta().load(x),
            }
    
            result = switch[value['data_type']](value['data'])
            if result.errors:
                raise ValidationError(result.errors)

    4. 参考文献

  • 相关阅读:
    Java初学—类与对象
    linux dd命令测试U盘读写速度
    路由器的几种访问方式
    制作Linux启动盘并安装Linux系统到实体机
    RAID阵列与LVM逻辑卷组创建
    有关Linux下库的概念、生成和升级和使用等
    LInux中VIM的使用和定制
    如何通过mount命令挂载存储设备
    硬盘分区和系统启动
    RAID阵列与LVM逻辑卷组原理
  • 原文地址:https://www.cnblogs.com/wangao1236/p/10899606.html
Copyright © 2011-2022 走看看