Custom Fields

There are three ways to create a custom-formatted field for a Schema:

The method you choose will depend on the manner in which you intend to reuse the field.

Creating A Field Class

To create a custom field class, create a subclass of marshmallow.fields.Field and implement its _serialize and/or _deserialize methods.

from marshmallow import fields, ValidationError


class PinCode(fields.Field):
    """Field that serializes to a string of numbers and deserializes
    to a list of numbers.
    """

    def _serialize(self, value, attr, obj, **kwargs):
        if value is None:
            return ""
        return "".join(str(d) for d in value)

    def _deserialize(self, value, attr, data, **kwargs):
        try:
            return [int(c) for c in value]
        except ValueError as error:
            raise ValidationError("Pin codes must contain only digits.") from error


class UserSchema(Schema):
    name = fields.String()
    email = fields.String()
    created_at = fields.DateTime()
    pin_code = PinCode()

Method Fields

A Method field will serialize to the value returned by a method of the Schema. The method must take an obj parameter which is 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

A Function field will serialize the value of a function that is passed directly to it. Like a Method field, the function must take a single argument obj.

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

Method and Function field deserialization

Both Function and Method receive an optional deserialize argument which defines how the field should be deserialized. The method or function passed to deserialize receives the input value for the field.

class UserSchema(Schema):
    # `Method` takes a method name (str), Function takes a 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["balance"]  # => 100.0

Adding Context to Method and Function Fields

A Function or Method field may need information about its environment to know how to serialize a value.

In these cases, you can set the context attribute (a dictionary) of a Schema. Function and Method fields will have access to this dictionary.

As an example, you might want your UserSchema to output whether or not a User is the author of a Blog or whether a certain word appears in a Blog's title.

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")

    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}
result = schema.dump(user)
result["is_author"]  # => True
result["likes_bikes"]  # => True

Customizing Error Messages

Validation error messages for fields can be configured at the class or instance level.

At the class level, default error messages are defined as a mapping from error codes to error messages.

from marshmallow import fields


class MyDate(fields.Date):
    default_error_messages = {"invalid": "Please provide a valid date."}

Note

A Field's default_error_messages dictionary gets merged with its parent classes’ default_error_messages dictionaries.

Error messages can also be passed to a Field's constructor.

from marshmallow import Schema, fields


class UserSchema(Schema):
    name = fields.Str(
        required=True, error_messages={"required": "Please provide a name."}
    )

Next Steps

  • Need to add schema-level validation, post-processing, or error handling behavior? See the Extending Schemas page.

  • For example applications using marshmallow, check out the Examples page.