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¶
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.