new·Earn with mozg — 20% of every monthSend somebody here and take a fifth of every plan payment they make, for as long as they keep paying — not a bounty on the first invoice. Your handle is the link, the window is thirty days, and the commission lands on your balance the second they pay. Free to join: if you have signed in, you already have the link. mozg.sh/earnall news →
mozg.beta
Sign in

Pydantic · Concepts · all subjects

serializers

20 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Only one serializer per field or model

Only one serializer can be defined per field or model. It is not possible to combine multiple serializers together, including both plain and wrap serializers.

Plain field serializers called unconditionally

Plain field serializers are called unconditionally to serialize a field. The serialization logic for types supported by Pydantic will not be called. Using plain serializers is useful for arbitrary types and for specifying custom serialization logic. A plain serializer is a callable that takes the value to be serialized and returns the serialized value.

Plain field serializer example with Annotated

from typing import Annotated, Any from pydantic import BaseModel, PlainSerializer def ser_number(value: Any) -> Any: if isinstance(value, int): return value * 2 else: return value class Model(BaseModel): number: Annotated[int, PlainSerializer(ser_number)] print(Model(number=4).model_dump()) #> {'number': 8} This example shows a plain field serializer using the Annotated pattern that doubles integer values.

Plain field serializer example with decorator

from typing import Any from pydantic import BaseModel, field_serializer class Model(BaseModel): number: int @field_serializer('number', mode='plain') def ser_number(self, value: Any) -> Any: if isinstance(value, int): return value * 2 else: return value print(Model(number=4).model_dump()) #> {'number': 8} This example shows a plain field serializer using the decorator pattern. The 'plain' mode is the default and can be omitted.

Wrap field serializers provide flexibility

Wrap field serializers give flexibility to customize serialization behavior by allowing code to run before or after Pydantic serialization logic. Such serializers must have a mandatory extra handler parameter, which is a callable taking the value to be serialized. The handler internally delegates serialization to Pydantic. You are free to not call the handler at all.

Wrap field serializer example with Annotated

from typing import Annotated, Any from pydantic import BaseModel, SerializerFunctionWrapHandler, WrapSerializer def ser_number(value: Any, handler: SerializerFunctionWrapHandler) -> int: return handler(value) + 1 class Model(BaseModel): number: Annotated[int, WrapSerializer(ser_number)] print(Model(number=4).model_dump()) #> {'number': 5} This example shows a wrap field serializer using the Annotated pattern that adds 1 to the serialized value.

Wrap field serializer example with decorator

from typing import Any from pydantic import BaseModel, SerializerFunctionWrapHandler, field_serializer class Model(BaseModel): number: int @field_serializer('number', mode='wrap') def ser_number(self, value: Any, handler: SerializerFunctionWrapHandler) -> int: return handler(value) + 1 print(Model(number=4).model_dump()) #> {'number': 5} This example shows a wrap field serializer using the decorator pattern.

Annotated pattern for reusable serializers

Using the annotated pattern for field serializers makes them reusable across multiple models and fields. You can define a type alias with a serializer and use it in multiple model fields. This also allows applying serializers to specific parts of annotations, such as list items.

Reusable serializer type alias example

from typing import Annotated from pydantic import BaseModel, Field, PlainSerializer DoubleNumber = Annotated[int, PlainSerializer(lambda v: v * 2)] class Model1(BaseModel): my_number: DoubleNumber class Model2(BaseModel): other_number: Annotated[DoubleNumber, Field(description='My other number')] class Model3(BaseModel): list_of_even_numbers: list[DoubleNumber] This example demonstrates creating a reusable serializer type alias that can be used across multiple models and applied to collection items.

Decorator pattern for field serializers on multiple fields

Using the @field_serializer decorator allows applying a serializer function to multiple fields at once by passing multiple field names as arguments.

Apply field serializer to multiple fields example

from pydantic import BaseModel, field_serializer class Model(BaseModel): f1: str f2: str @field_serializer('f1', 'f2', mode='plain') def capitalize(self, value: str) -> str: return value.capitalize() This example shows a field serializer applied to multiple fields using the decorator pattern.

Field serializer wildcard for all fields

The @field_serializer decorator supports passing '*' as the field name argument to apply the serializer to all fields, including those defined in subclasses.

Field serializer check_fields argument

By default, the @field_serializer decorator ensures the provided field name(s) are defined on the model. The check_fields argument can be set to False to disable this check during class creation. This is useful when the field serializer is defined on a base class and the field is expected to exist on subclasses.

Plain model serializers

Plain model serializers are called unconditionally to serialize the model. They use the @model_serializer decorator with mode='plain' (the default). A plain model serializer can return a value that isn't a dictionary, though this may cause type checking issues.

Plain model serializer example

from pydantic import BaseModel, model_serializer class UserModel(BaseModel): username: str password: str @model_serializer(mode='plain') def serialize_model(self) -> str: return f'{self.username} - {self.password}' print(UserModel(username='foo', password='bar').model_dump()) #> foo - bar This example shows a plain model serializer that returns a string representation instead of a dictionary.

Wrap model serializers

Wrap model serializers give flexibility to customize serialization behavior by allowing code to run before or after Pydantic serialization logic. They use the @model_serializer decorator with mode='wrap'. Such serializers must have a mandatory extra handler parameter, a callable taking the instance of the model as an argument.

Wrap model serializer example

from pydantic import BaseModel, SerializerFunctionWrapHandler, model_serializer class UserModel(BaseModel): username: str password: str @model_serializer(mode='wrap') def serialize_model(self, handler: SerializerFunctionWrapHandler) -> dict[str, object]: serialized = handler(self) serialized['fields'] = list(serialized) return serialized print(UserModel(username='foo', password='bar').model_dump()) #> {'username': 'foo', 'password': 'bar', 'fields': ['username', 'password']} This example shows a wrap model serializer that augments the default serialization with additional information.

Serialization info parameter in serializers

Both field and model serializer callables in all modes can optionally take an extra info argument. This provides useful extra information including user-defined context, the current serialization mode ('python' or 'json'), serialization parameters (exclude_unset, serialize_as_any), and for field serializers, the current field name.

Serialization context usage

You can pass a context object to serialization methods like model_dump() and model_dump_json(), which can be accessed inside serializer functions via the info.context property.

Serialization context example

from pydantic import BaseModel, FieldSerializationInfo, field_serializer class Model(BaseModel): text: str @field_serializer('text', mode='plain') @classmethod def remove_stopwords(cls, v: str, info: FieldSerializationInfo) -> str: if isinstance(info.context, dict): stopwords = info.context.get('stopwords', set()) v = ' '.join(w for w in v.split() if w.lower() not in stopwords) return v model = Model(text='This is an example document') print(model.model_dump()) #> {'text': 'This is an example document'} print(model.model_dump(context={'stopwords': ['this', 'is', 'an']})) #> {'text': 'example document'} This example demonstrates passing and using a context object in a field serializer.

Give your agent this brain