Field-Level Serialization Control
You can customize how individual fields are serialized in models, dataclasses, and typed dicts by configuring field-level attributes in the core schema. This includes renaming fields with aliases, excluding fields entirely, or applying conditional logic based on the field's value or the serialization context.
Customizing Field Serialization with Aliases and Exclusion
To control basic serialization behavior, use the serialization_alias, serialization_exclude, and serialization_exclude_if parameters within ModelField, DataclassField, or TypedDictField.
from pydantic_core import SchemaSerializer, core_schema
class BasicModel:
def __init__(self, a: int, b: str, c: str):
self.a = a
self.b = b
self.c = c
schema = core_schema.model_schema(
BasicModel,
core_schema.model_fields_schema(
{
# Rename 'a' to 'alpha' in the output
'a': core_schema.model_field(
core_schema.int_schema(),
serialization_alias='alpha'
),
# Exclude 'b' if it contains the string 'secret'
'b': core_schema.model_field(
core_schema.str_schema(),
serialization_exclude_if=lambda x: 'secret' in x
),
# Always exclude 'c' from serialization
'c': core_schema.model_field(
core_schema.str_schema(),
serialization_exclude=True
),
}
),
)
s = SchemaSerializer(schema)
# 'a' is aliased, 'b' is included, 'c' is excluded
assert s.to_python(BasicModel(a=1, b='public', c='hidden'), by_alias=True) == {'alpha': 1, 'b': 'public'}
# 'b' is excluded because it matches the condition
assert s.to_python(BasicModel(a=1, b='secret_info', c='hidden'), by_alias=True) == {'alpha': 1}
Including Computed Fields
You can include properties or methods in the serialized output by defining ComputedField entries in your schema. These fields support aliases and conditional exclusion just like standard fields.
class Rectangle:
def __init__(self, width: int, height: int):
self.width = width
self.height = height
def area(self) -> int:
return self.width * self.height
schema = core_schema.model_schema(
Rectangle,
core_schema.model_fields_schema(
{
'width': core_schema.model_field(core_schema.int_schema()),
'height': core_schema.model_field(core_schema.int_schema()),
},
computed_fields=[
# 'area' is a method on the class, serialized as 'Area'
core_schema.computed_field(
'area',
core_schema.int_schema(),
alias='Area'
),
],
),
)
s = SchemaSerializer(schema)
rect = Rectangle(3, 4)
assert s.to_python(rect, by_alias=True) == {'width': 3, 'height': 4, 'Area': 12}
Advanced Customization with FieldSerializationInfo
For complex serialization logic, you can use a custom field serializer that receives FieldSerializationInfo. This provides access to the field name and global serialization settings like the current mode (python or json).
To use this, define a function that accepts the object, the field value, and an info argument, then register it using plain_serializer_function_ser_schema with is_field_serializer=True and info_arg=True.
from typing import Any, TypedDict
from pydantic_core import core_schema, SchemaSerializer
class User(TypedDict):
id: int
username: str
def serialize_user_id(data: User, v: Any, info: core_schema.FieldSerializationInfo) -> str:
# Access the field name and the current serialization mode
prefix = 'ID' if info.mode == 'python' else 'json_id'
return f'{prefix}-{info.field_name}-{v}'
schema = core_schema.typed_dict_schema(
{
'id': core_schema.typed_dict_field(
core_schema.int_schema(
serialization=core_schema.plain_serializer_function_ser_schema(
serialize_user_id,
is_field_serializer=True,
info_arg=True
)
)
),
'username': core_schema.typed_dict_field(core_schema.str_schema())
}
)
s = SchemaSerializer(schema)
user = {'id': 123, 'username': 'jdoe'}
# In python mode
assert s.to_python(user)['id'] == 'ID-id-123'
# In json mode
import json
assert json.loads(s.to_json(user))['id'] == 'json_id-id-123'
Troubleshooting
- Alias Overrides: The
by_aliasargument passed toto_pythonorto_jsonat runtime typically overrides theserialize_by_aliassetting inCoreConfig. If your aliases aren't appearing, ensure you are passingby_alias=Trueto the serializer call. - Exclusion Priority: If both
serialization_exclude=Trueandserialization_exclude_ifare provided, the field will be excluded if either condition is met. - Field Name Access: When using custom serializers, always use
info.field_namefromFieldSerializationInfoinstead of hardcoding the field name, as this ensures the serializer remains reusable and correct even if the field is renamed in the schema.