Search code examples
pythonpydanticpydantic-v2

pydantic: exclude computed field from dump


In pydantic v2, the following code:

from __future__ import annotations
import pydantic
from pprint import pprint


class System(pydantic.BaseModel):
    id: int
    name: str
    subsystems: list[System] | None = None

    @pydantic.computed_field()
    @property
    def computed(self) -> str:
        return self.name.upper()


systems = System(
    id=1,
    name="Main system",
    subsystems=[
        System(id=2, name="Subsystem A"),
        System(id=3, name="Subsystem B"),
    ],
)
pprint(systems.model_dump(), indent=2)

prints:

{ 'computed': 'MAIN SYSTEM',
  'id': 1,
  'name': 'Main system',
  'subsystems': [ { 'computed': 'SUBSYSTEM A',
                    'id': 2,
                    'name': 'Subsystem A',
                    'subsystems': None},
                  { 'computed': 'SUBSYSTEM B',
                    'id': 3,
                    'name': 'Subsystem B',
                    'subsystems': None}]}

I want to exclude the computed field computed.

pprint(systems.model_dump(exclude={'computed': True}), indent=2)

prints only root element without computed:

{ 'id': 1,
  'name': 'Main system',
  'subsystems': [ { 'computed': 'SUBSYSTEM A',
                    'id': 2,
                    'name': 'Subsystem A',
                    'subsystems': None},
                  { 'computed': 'SUBSYSTEM B',
                    'id': 3,
                    'name': 'Subsystem B',
                    'subsystems': None}]}

How to exclude computed field (e.g. computed) from dump?

I want to serialize via .model_dump() because:

  • I have many models and models those include System are serialized via .model_dump() method as well.
  • .model_dump() has some useful parameters like exclude_defaults, by_alias and more. I use them as well.

Solution

  • According to the documentation on computed_field:

    computed_field

    Decorator to include property and cached_property when serializing models or dataclasses.

    This is useful for fields that are computed from other fields, or for fields that are expensive to compute and should be cached.

    In other words, if don't want to include (= exclude) a field we shouldn't use computed_field decorator:

    from __future__ import annotations
    import pydantic
    from pprint import pprint
    
    class System(pydantic.BaseModel):
        id: int
        name: str
        subsystems: list[System] | None = None
    
        # comment or remove it
        # @pydantic.computed_field()
        @property
        def computed(self) -> str:
            return self.name.upper()
    
    
    systems = System(
        id=1,
        name="Main system",
        subsystems=[
            System(id=2, name="Subsystem A"),
            System(id=3, name="Subsystem B"),
        ],
    )
    pprint(systems.model_dump(), indent=2)
    print(systems.computed)  # but it is still there
    

    Output is:

    { 'id': 1,
      'name': 'Main system',
      'subsystems': [ {'id': 2, 'name': 'Subsystem A', 'subsystems': None},
                      {'id': 3, 'name': 'Subsystem B', 'subsystems': None}]}
    MAIN SYSTEM