marshmallowのカスタムフィールド


カスタムfieldを作成するには、3つの方法があります.
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.Methodおよびfields.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', '[email protected]')
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.'}
    )