Skip to main content

Implementing Computed Fields

Computed fields allow you to include derived values—such as Python properties or cached properties—in the serialized output of your objects. These fields are calculated during serialization and are not part of the validation schema.

Defining Computed Fields in Models

To include a computed field in a model, define it using core_schema.computed_field within the computed_fields list of a model_fields_schema.

from functools import cached_property
from pydantic_core import SchemaSerializer, core_schema

class Model:
def __init__(self, x: int, y: int):
self.x = x
self.y = y

@cached_property
def y_formatted(self) -> str:
return f'{self.y:_}'

schema = core_schema.model_schema(
Model,
core_schema.model_fields_schema(
{
'x': core_schema.model_field(core_schema.int_schema()),
'y': core_schema.model_field(core_schema.int_schema()),
},
computed_fields=[
core_schema.computed_field('y_formatted', core_schema.str_schema())
],
)
)

serializer = SchemaSerializer(schema)
instance = Model(x=1000, y=2000)
assert serializer.to_python(instance) == {
'x': 1000,
'y': 2000,
'y_formatted': '2_000'
}

Using Computed Fields with Dataclasses

For dataclasses, computed fields are added to the dataclass_args_schema. The property_name must match the name of a @property defined on the dataclass.

import dataclasses
from pydantic_core import SchemaSerializer, core_schema

@dataclasses.dataclass
class FooProp:
a: str
b: bytes

@property
def c(self) -> str:
return f'{self.a} {self.b.decode()}'

schema = core_schema.dataclass_schema(
FooProp,
core_schema.dataclass_args_schema(
'FooProp',
[
core_schema.dataclass_field(name='a', schema=core_schema.str_schema()),
core_schema.dataclass_field(name='b', schema=core_schema.bytes_schema()),
],
computed_fields=[core_schema.computed_field('c', core_schema.str_schema())],
),
['a', 'b'],
)

serializer = SchemaSerializer(schema)
instance = FooProp(a='hello', b=b'more')
assert serializer.to_python(instance) == {
'a': 'hello',
'b': b'more',
'c': 'hello more'
}

Customizing Serialization

Using Aliases

You can use the alias parameter to change the key name used in the serialized output.

schema = core_schema.model_fields_schema(
{'x': core_schema.model_field(core_schema.int_schema())},
computed_fields=[
core_schema.computed_field(
'x_plus_one',
core_schema.int_schema(),
alias='x1'
)
],
)
# Serialized output will use 'x1' instead of 'x_plus_one'

Conditional Serialization

The serialization_exclude_if parameter allows you to skip a computed field based on its value. The predicate function receives the result of the property.

def exclude_if_none(value):
return value is None

schema = core_schema.computed_field(
'maybe_value',
core_schema.str_schema(),
serialization_exclude_if=exclude_if_none
)

Troubleshooting

Computed Fields Missing in Output

If your computed fields are not appearing in the serialized output, check the following:

  1. Round Trip Mode: Computed fields are automatically excluded if round_trip=True is passed to the serializer (e.g., serializer.to_python(obj, round_trip=True)). This is because computed fields cannot be validated back into the object.
  2. Explicit Exclusion: Ensure exclude_computed_fields=True is not being passed to the serialization method.
  3. Schema Placement: Computed fields are only supported within model_fields_schema, dataclass_args_schema, and typed_dict_schema. They will not function if placed in other schema types.
  4. Property Access: pydantic-core uses getattr(instance, property_name) to retrieve the value. Ensure the property is accessible and does not raise an exception during access.