美文网首页Python
marshmallow轻量自动化验证和序列化

marshmallow轻量自动化验证和序列化

作者: 极光火狐狸 | 来源:发表于2017-04-17 09:38 被阅读545次

    源代码

    import functools
    from tornado.web import HTTPError
    from marshmallow_peewee import ModelSchema
    from marshmallow.fields import Field
    from marshmallow_peewee import Related
    from marshmallow.validate import (
        URL, Email, Range, Length, Equal, Regexp,
        Predicate, NoneOf, OneOf, ContainsOnly
    )
    
    URL.default_message = '无效的链接'
    Email.default_message = '无效的邮箱地址'
    Range.message_min = '不能小于{min}'
    Range.message_max = '不能小于{max}'
    Range.message_all = '不能超过{min}和{max}这个范围'
    Length.message_min = '长度不得小于{min}位'
    Length.message_max = '长度不得大于{max}位'
    Length.message_all = '长度不能超过{min}和{max}这个范围'
    Length.message_equal = '长度必须等于{equal}位'
    Equal.default_message = '必须等于{other}'
    Regexp.default_message = '非法输入'
    Predicate.default_message = '非法输入'
    NoneOf.default_message = '非法输入'
    OneOf.default_message = '无效的选择'
    ContainsOnly.default_message = '一个或多个无效的选择'
    Field.default_error_messages = {
            'required': '该字段是必填字段',
            'type': '无效的输入类型',
            'null': '字段不能为空',
            'validator_failed': '无效的值'
    }
    
    
    def validate_schema(_model, **schema_kwargs):
    
        """
        用于检查参数正确性。
    
        :param _model: 数据库模块,用于绑定字段校验。
        :param schema_kwargs:  根据marshmallow.schema.Schema的
                                参数要求进行要求,下面是详细参数列表:
                                extra=None
                                only=()
                                exclude=()
                                prefix=''
                                strict=None
                                many=False
                                context=None
                                load_only=()
                                dump_only=()
                                partial=False
        :return: 校验正确则执行handler,校验失败则返回错误信息。
        """
    
        def decorator(f):
            @functools.wraps(f)
            def wrapper(self, *args, **kwargs):
    
                class CommonSchema(ModelSchema):
    
                    class Meta:
                        model = _model
    
                # 检查验证结果
                result, errors = (CommonSchema(**schema_kwargs)
                                  .load(self.plain_arguments()))
    
                # 当验证结果存在错误时, 返回错误信息.
                if errors:
                    msg = ['{}{}'.format(getattr(_model, k).verbose_name, v[0])
                           for k, v in errors.items()]
                    raise HTTPError(status_code=400, log_message='\n'.join(msg))
    
                # 当验证结果正确时, 执行handler.
                return f(self, *args, **kwargs)
            return wrapper
        return decorator
    
    
    def serializer_schema(_model, *related, **schema_kwargs):
        """
        用于序列化。
        :param _model: 数据库模块,用于绑定字段校验。
        :param related: 声明那些关联字段是需要一起序列化的,参数格式如下:
                         [
                         # 表示外键
                         (field_name, None),
                         # 表示该字段为不是关联字段,但序列化需要存在的字段.
                         (field_name, callback)
                         ]
        :param schema_kwargs: 根据marshmallow.schema.Schema的
                                参数要求进行要求,下面是详细参数列表:
                                extra=None
                                only=()
                                exclude=()
                                prefix=''
                                strict=None
                                many=False
                                context=None
                                load_only=()
                                dump_only=()
                                partial=False
        :return: 返回经过序列化后的数据集。
        """
    
        class CommonSchema:
            class Meta:
                model = None
    
        # 绑定类对象
        CommonSchema.Meta.model = _model
        [setattr(CommonSchema, field, callback())
         if callback else setattr(CommonSchema, field, Related())
         for field, callback in related]
    
        # 混入
        schema_cls = type(
            str('CommonSchema'), (CommonSchema, ModelSchema), {}
        )
    
        return schema_cls(**schema_kwargs)
    
    

    目的

    针对marshmallow和peewee进行数据库字段整合,便于自动映射、验证和序列化行为。
    通过下面的实现,可以简化一些简单的定义工作(复杂的暂时不支持),例如: 验证post
    表单参数可以通过指定validate_schema来自动完成检查行为,而不需要去定义
    ValidateSchema;序列化peewee查询结果可以通过serializer_schema来自动完成结构
    体自动绑定,而不需要去定义serializerSchema结构体。(警告: 目前这两个方法只
    支持简单的自动检查和序列化,非常复杂的场景还是需要手动去定义结构体),这里
    列出一些使用方法:

    验证案例

    利用validate_schema对登录页面提交的参数进行验证。
    validate_schema的第一个参数 User 是一个models对象,装饰器默认会根据这个User。 对象自动映射和验证全部字段,通过利用only参数可以通知验证器仅验证哪几个字段。除了only参数之外,常用的还有 exclude和many参数。

    @route('/login')
    class Login(BaseHandler):
        # 装饰器在这里工作
        @validate_schema(User, only=('mobile', 'password'))      
        def post(self):
            # 验证用户名是否存在。
            
            # 验证密码是否正确。
            
            # local.storage/cookie/session保存用户信息。
            self.write('ok')
    

    序列化案例:

    from marshmallow import pprint
    s = (User.select()
         .where(User.id=='1')
         .get())
    
    result, errors = serializer_schema(User).dump(s)
    pprint(result)
    
    
    # 输出结果
    {
     'created_at': 'XXX',
     'email': None,
     'id': '1',
     'is_active': True,
     'mobile': 'XXXXXX',
     'name': 'XX',
     'password': 'XXXXXXXXXX'
    }
    

    利用only参数来控制数据结果

    result, errors = serializer_schema(User, only=('mobile', 'email', 'name')).dump(s)
    pprint(result)
    # 输出结果
    {'email': None, 'mobile': 'XXXXXX', 'name': 'XX'}
    

    利用exclude参数来控制数据结果

    result, errors = serializer_schema(User, exclude=('mobile', )).dump(s)
    pprint(result)
    # 输出结果
    {
     'created_at': 'XXX',
     'email': None,
     'id': '1',
     'is_active': True,
     'name': 'XX',
     'password': 'XXXXXXXXXX'
    }
    

    一对多关系处理

    result, errors = serializer_schema(User, *[('logs', None), ], exclude=('password', )).dump(s)
    pprint(result)
    
    
    # 查看结果
    {
     'created_at': 'XX',
     'email': None,
     'id': 1,
     'is_active': True,
     'logs': [{'created_at': 'XX',
               'id': 1,
               'ip': '111',
               'user': 1}],
     'mobile': 'XXXXXX',
     'name': 'XX',
    }
    

    多对一关系处理

    s = (UserLog.select().where(UserLog.id=='1').get())
    pprint(serializer_schema(UserLog, *[('user', None)]).dump(s)[0])
    # 查看结果
    {'created_at': 'XX',
     'id': 1,
     'ip': '111',
     'user': {
              'created_at': '2017-01-23T11:40:19.534108+00:00',
              'email': None,
              'id': 1,
              'is_active': True,
              'mobile': 'XXXXXX',
              'name': 'XX',
              'password': 'XXXXXXXXXX'}}
    

    未完待续(多对多关系处理)

    未完待续(复杂的多表联合处理)

    相关文章

      网友评论

      本文标题:marshmallow轻量自动化验证和序列化

      本文链接:https://www.haomeiwen.com/subject/meazattx.html