Custom Field for marshmallow

There are three ways to create custom field s.

Create a subclass of the Field class

Create a subclass inheriting from the marshmallow.fields.Field class and implement the _serialize and/or _deserialize methods:

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 serializes the return value of a method in the schema that must receive an obj parameter for the object to be serialized:

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

The fields.Function passes serialization to the return value of the function it passes and also receives an obj parameter:

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

Deserialization of Method and Function

Both fields.Method and fields.Function receive an optional deserialize parameter that defines how to deserialize a field:

class UserSchema(Schema):
    # Method receives method name of string type, Function receives callable object
    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

Add context for Method and Function

Environment information may be required for Function and Method serialization.The context property (dict object) can be set for the schema, and Function and Method can access this dictionary.

The following example determines whether a User object is the author of a Blog object and whether the bicycle word appears in the title property of a Blog:

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

Custom Error Information

Error information generated by field validation can be configured at the class or instance level.

At the class level, default_error_messages can be defined as dictionary mappings of error codes and information:

from marshmallow import fields

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

When the Field class is instantiated, pass a parameter (dict object) to the error_messages parameter:

from marshmallow import Schema, fields

class UserSchema(Schema):

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

Tags: Python Lambda Attribute

Posted on Thu, 07 Nov 2019 10:07:20 -0500 by srikanth03565