有三种方式创建自定义的field。

创建Field类的子类

创建继承自marshmallow.fields.Field类的子类并实现_serialize和/或_deserialize方法:

from marshmallow import fields, Schema

class Titlecased(fields.Field):
    def _serialize(self, value, attr, obj):
        if value is None:
            return ''
        return value.title()

class UserSchema(Schema):
    name = fields.String()
    email = fields.String()
    created_at = fields.DateTime()
    titlename = TitleCased(attribute="name")

Method Fields

fields.Method将序列化schema中某个方法的返回值,该方法必须接收一个要进行序列化的对象的参数obj

class UserSchema(Schema):
    name = fields.String()
    email = fields.String()
    created_at = fields.DateTime()
    since_created = fields.Method("get_days_since_created")

    def get_days_since_created(self, obj):
        return dt.datetime.now().day - obj.created_at.day

Function Fields

fields.Function将序列化传递给它的函数的返回值,也接收一个obj参数:

class UserSchema(Schema):
    name = fields.String()
    email = fields.String()
    created_at = fields.DateTime()
    uppername = fields.Function(lambda obj: obj.name.upper())

Method和Function的反序列化

fields.Methodfields.Function都接收一个可选的deserialize参数,该参数定义了如何反序列化字段:

class UserSchema(Schema):
    # Method接收字符串类型的方法名, Function接收callable对象
    balance = fields.Method('get_balance', deserialize='load_balance')

    def get_balance(self, obj):
        return obj.income - obj.debt

    def load_balance(self, value):
        return float(value)

schema = UserSchema()
result = schema.load({'balance': '100.00'})
result.data['balance']  # => 100.0

为Method和Function添加上下文

Function和Method序列化时可能需要相关环境信息。可以为schema设置context属性(dict对象),Function和Method可以访问此字典。

下面的例子判断某个User对象是否是某个Blog对象的作者,以及Blog的title属性是否出现bicycle单词:

class UserSchema(Schema):
    name = fields.String()
    # Function fields optionally receive context argument
    is_author = fields.Function(lambda user, context: user == context['blog'].author)
    likes_bikes = fields.Method('writes_about_bikes')

    # Method fields also optionally receive context argument
    def writes_about_bikes(self, user):
        return 'bicycle' in self.context['blog'].title.lower()

schema = UserSchema()

user = User('Freddie Mercury', 'fred@queen.com')
blog = Blog('Bicycle Blog', author=user)

schema.context = {'blog': blog}
data, errors = schema.dump(user)
data['is_author']  # => True
data['likes_bikes']  # => True

自定义错误信息

字段验证产生的错误信息可以在类级别或实例级别配置。

在类级别时,default_error_messages可以定义为错误码和错误信息的字典映射:

from marshmallow import fields

class MyDate(fields.Date):
    default_error_messages = {
        '400001': 'Please provide a valid date.',
    }

在Field类实例化时,给error_messages参数传参(dict对象):

from marshmallow import Schema, fields

class UserSchema(Schema):

    name = fields.Str(
        required=True,
        error_messages={'required': 'Please provide a name.'}
    )

当麻的小红箱
71 声望11 粉丝

spec!