from marshmallow import (
Schema as Schema_, fields, pre_load, post_load, post_dump,
)
from marshmallow_sqlalchemy.schema import SQLAlchemyAutoSchemaMeta
from flask_marshmallow.sqla import \
SQLAlchemyAutoSchema as SQLAlchemyAutoSchema_
from marshmallow_enum import EnumField
[文档]class ORMSchema(SQLAlchemyAutoSchema_):
"""Base schema for ModelSchema. See `webargs/issues/126
<https://github.com/sloria/webargs/issues/126>`_.
Example::
from hobbit_core.schemas import ORMSchema
class UserSchema(ORMSchema):
class Meta:
model = User
load_only = ('password')
``@use_kwargs(UserSchema())`` use in combination with ``load_only``::
@bp.route('/users/', methods=['POST'])
@use_kwargs(UserSchema())
def create_user(username, password):
pass
"""
@post_load()
def make_instance(self, data, many, **kwargs):
return data
[文档]class SchemaMixin(object):
"""Add ``id``, ``created_at``, ``updated_at`` fields to schema,
default ``dump_only=True``.
Example::
from marshmallow import Schema
from hobbit_core.schemas import SchemaMixin
class UserSchema(Schema, SchemaMixin):
pass
"""
id = fields.Int(dump_only=True)
created_at = fields.DateTime('%Y-%m-%d %H:%M:%S', dump_only=True)
updated_at = fields.DateTime('%Y-%m-%d %H:%M:%S', dump_only=True)
class Meta:
strict = True
ordered = False
dateformat = '%Y-%m-%d %H:%M:%S'
[文档]class PagedSchema(Schema_):
"""Base schema for list api pagination.
Example::
from marshmallow import fields
from hobbit_core.schemas import PagedSchema
from . import models
from .exts import ma
class UserSchema(ma.ModelSchema):
class Meta:
model = models.User
class PagedUserSchema(PagedSchema):
items = fields.Nested('UserSchema', many=True)
paged_user_schemas = PagedUserSchema()
"""
total = fields.Int()
page = fields.Int(missing=1, default=1)
page_size = fields.Int(missing=10, default=10)
[文档] class Meta:
strict = True
class EnumSetMeta(SQLAlchemyAutoSchemaMeta):
"""EnumSetMeta is a metaclass that can be used to auto generate load and
dump func for EnumField.
"""
@classmethod
def gen_func(cls, decorator, field_name, enum, verbose=True):
@decorator
def wrapper(self, data, many, **kwargs):
if data.get(field_name) is None:
return data
if decorator is pre_load:
data[field_name] = enum.load(data[field_name])
elif decorator is post_dump:
data[field_name] = enum.dump(data[field_name], verbose)
else:
raise Exception(
'hobbit_core: decorator `{}` not support'.format(
decorator))
return data
return wrapper
def __new__(cls, name, bases, attrs):
schema = SQLAlchemyAutoSchemaMeta.__new__(
cls, name, tuple(bases), attrs)
verbose = getattr(schema.Meta, 'verbose', True)
setattr(schema.Meta, 'dateformat', '%Y-%m-%d %H:%M:%S')
for field_name, declared in schema._declared_fields.items():
if not isinstance(declared, EnumField):
continue
setattr(schema, 'load_{}'.format(field_name), cls.gen_func(
pre_load, field_name, declared.enum))
setattr(schema, 'dump_{}'.format(field_name), cls.gen_func(
post_dump, field_name, declared.enum, verbose=verbose))
return schema
[文档]class ModelSchema(ORMSchema, SchemaMixin, metaclass=EnumSetMeta):
"""Base ModelSchema for ``class Model(db.SurrogatePK)``.
* Auto generate load and dump func for EnumField.
* Auto dump_only for ``id``, ``created_at``, ``updated_at`` fields.
* Auto set dateformat to ``'%Y-%m-%d %H:%M:%S'``.
* Auto use verbose for dump EnumField. See ``db.EnumExt``. You can define
verbose in ``Meta``.
Example::
class UserSchema(ModelSchema):
role = EnumField(RoleEnum)
class Meta:
model = User
data = UserSchema().dump(user).data
assert data['role'] == {'key': 1, 'label': 'admin', 'value': '管理员'}
"""
pass