Search code examples
pythonjsonpydanticpydantic-v2

Pydantic/JSON: do not serialize fields with default value


I have a class with a member that has a default value.

I do not wish the default value to be part of the serialization.

Example:

import json
from typing import List
from pydantic import BaseModel
from pydantic.json import pydantic_encoder

class Animal(BaseModel):
   name: str
   legs: int
   tails: int = 1

class AnimalList(BaseModel):
    animals: List[Animal]

animals = AnimalList(animals=[
   Animal(name='dog', legs=4),
   Animal(name='human', legs=2, tails=0)
])

j = json.dumps(animals, default=pydantic_encoder)

print(j)

animals = AnimalList(**json.loads(j))

for animal in animals.animals:
    print(f"The {animal.name} has {animal.legs} legs and {animal.tails} tails.")

This produces the following output:

{"animals": [{"name": "dog", "legs": 4, "tails": 1}, {"name": "human", "legs": 2, "tails": 0}]}
The dog has 4 legs and 1 tails.
The human has 2 legs and 0 tails.

I wish to see the following output instead (the default "tails": 1 for the dog being removed):

{"animals": [{"name": "dog", "legs": 4}, {"name": "human", "legs": 2, "tails": 0}]}
The dog has 4 legs and 1 tails.
The human has 2 legs and 0 tails.

Solution

  • You should be able to handle it with exclude_defaults parameter from model_dump method :

    animals = AnimalList(animals=[Animal(name="dog", legs=4), Animal(name="human", legs=2, tails=0)])
    without_defaults = animals.model_dump(exclude_defaults=True)
    print(without_defaults)
    j = json.dumps(without_defaults, default=pydantic_encoder)
    
    

    But usually you would prefer to use it with tail : int | None = Field(default=None), to have consistency between your pydantic instances and your dumped json. Because in this case you have :

    pydantic_instance.tail == 1
    dumped_json_then_loaded_back.get("tail") is None