marshmallow-polyfield
marshmallow-polyfield is an unofficial extension to Marshmallow (version 3+) that enables defining polymorphic fields within your schemas. It allows for serialization and deserialization of objects that can have different underlying types, mapping them to appropriate Marshmallow schemas based on a discriminator field. The current version is 5.11, and it maintains an active release cadence to ensure compatibility with recent Marshmallow versions.
Common errors
-
AttributeError: 'Field' object has no attribute '_declared_fields'
cause This error often indicates that you are running `marshmallow-polyfield` (which targets Marshmallow 3) with an older version of `marshmallow` (e.g., 2.x).fixUpgrade your `marshmallow` dependency to version 3.x or higher: `pip install --upgrade marshmallow` -
KeyError: 'type_field_value'
cause This usually occurs during deserialization when the value of the `lookup_field` in the input data does not match any of the keys defined in your `deserialization_schema_map`.fixVerify that the `lookup_field` name in your `PolyField` definition matches the key in your input data, and that its value corresponds to a key in `deserialization_schema_map`. -
TypeError: __init__() missing 1 required positional argument: 'lookup_field'
cause You've attempted to initialize `PolyField` without providing the mandatory `lookup_field` argument, which tells it which field to use for type discrimination.fixAdd the `lookup_field` argument to your `PolyField` instantiation, specifying the name of the field that determines the object's type (e.g., `lookup_field='object_type'`).
Warnings
- breaking marshmallow-polyfield requires Marshmallow 3.x. Using it with Marshmallow 2.x will lead to various AttributeErrors or unexpected behavior due to significant API changes between Marshmallow major versions.
- gotcha Incorrectly configured `lookup_field` or `schema_map` can lead to `KeyError` during deserialization or `ValidationError`. The `lookup_field` value in the data must exactly match a key in your `deserialization_schema_map`.
- gotcha `marshmallow-polyfield` does not automatically infer the type for serialization. Both `deserialization_schema_map` and `serialization_schema_map` must be provided and correctly configured for bidirectional polymorphism.
Install
-
pip install marshmallow-polyfield
Imports
- PolyField
from marshmallow_polyfield import PolyField
- PolySchema
from marshmallow_polyfield import PolySchema
Quickstart
from marshmallow import Schema, fields
from marshmallow_polyfield import PolyField
class Dog:
def __init__(self, name, breed):
self.name = name
self.breed = breed
self.animal_type = 'dog'
class Cat:
def __init__(self, name, color):
self.name = name
self.color = color
self.animal_type = 'cat'
class DogSchema(Schema):
name = fields.String(required=True)
breed = fields.String(required=True)
animal_type = fields.Constant('dog')
class CatSchema(Schema):
name = fields.String(required=True)
color = fields.String(required=True)
animal_type = fields.Constant('cat')
class AnimalSchema(Schema):
animal = PolyField(
deserialization_schema_map={
'dog': DogSchema,
'cat': CatSchema
},
serialization_schema_map={
'dog': DogSchema,
'cat': CatSchema
},
lookup_field='animal_type'
)
# --- Example Usage ---
dog_obj = Dog(name='Buddy', breed='Golden Retriever')
cat_obj = Cat(name='Whiskers', color='black')
# Serialization
poly_schema = AnimalSchema()
dog_data = poly_schema.dump({'animal': dog_obj})
cat_data = poly_schema.dump({'animal': cat_obj})
print(f"Serialized Dog: {dog_data}")
print(f"Serialized Cat: {cat_data}")
# Deserialization
dog_dict = {'animal_type': 'dog', 'name': 'Rex', 'breed': 'German Shepherd'}
cat_dict = {'animal_type': 'cat', 'name': 'Mittens', 'color': 'white'}
deserialized_dog = poly_schema.load({'animal': dog_dict})
deserialized_cat = poly_schema.load({'animal': cat_dict})
print(f"Deserialized Dog type: {type(deserialized_dog['animal'])}")
print(f"Deserialized Cat type: {type(deserialized_cat['animal'])}")