Skip to main content

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_alias argument passed to to_python or to_json at runtime typically overrides the serialize_by_alias setting in CoreConfig. If your aliases aren't appearing, ensure you are passing by_alias=True to the serializer call.
  • Exclusion Priority: If both serialization_exclude=True and serialization_exclude_if are provided, the field will be excluded if either condition is met.
  • Field Name Access: When using custom serializers, always use info.field_name from FieldSerializationInfo instead of hardcoding the field name, as this ensures the serializer remains reusable and correct even if the field is renamed in the schema.