Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
View this page
Toggle table of contents sidebar

# Custom fields

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

- Create a custom `Field` class

- Use a `Method` field

- Use a `Function` field

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

Warning

The `context` attribute is deprecated and will be removed in marshmallow 4. Use `contextvars.ContextVar` for passing context to fields, pre-/post-processing methods, and validators instead. marshmallow 4 will also provide an experimental helper API for using context.

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.