serialization#
model_dump#
convert a model to a dict. control what's included:
class Track(BaseModel):
id: int
title: str
artist_did: str
internal_score: float
track.model_dump() # all fields
track.model_dump(exclude={"internal_score"}) # omit internal fields
track.model_dump(include={"id", "title"}) # only these
track.model_dump(mode="json") # json-compatible types (datetimes → strings)
mode="json" is important — without it, you get python objects (datetime, Decimal). with it, everything is JSON-serializable.
model_dump_json / model_validate_json#
skip the dict intermediary for performance:
# serialize directly to JSON string
json_str = track.model_dump_json()
# deserialize directly from JSON string
track = Track.model_validate_json(json_str)
faster than json.dumps(track.model_dump()) because pydantic uses rust-based serialization internally.
useful for Redis caching:
await redis.set(cache_key, response.model_dump_json(), ex=300)
cached = await redis.get(cache_key)
if cached:
return AlbumResponse.model_validate_json(cached)
computed fields#
fields derived from other fields, included in serialization but not accepted as input:
from pydantic import BaseModel, computed_field
class Album(BaseModel):
tracks: list[Track]
@computed_field
@property
def track_count(self) -> int:
return len(self.tracks)
@computed_field
@property
def total_duration(self) -> float:
return sum(t.duration for t in self.tracks)
shows up in model_dump() and JSON output. not stored, always recomputed.
TypeAdapter for ad-hoc validation#
validate data without defining a full model:
from pydantic import TypeAdapter
int_adapter = TypeAdapter(int)
int_adapter.validate_python("42") # → 42
int_adapter.validate_python("abc") # → ValidationError
# useful for parsing env var fragments
StatusCode = Annotated[int, Field(ge=100, le=599)]
code_adapter = TypeAdapter(StatusCode)
code_adapter.validate_python(429) # → 429
code_adapter.validate_python(999) # → ValidationError
also handles complex types: TypeAdapter(list[int]), TypeAdapter(dict[str, float]).
response models in FastAPI#
FastAPI uses pydantic models for automatic request validation and response serialization:
class PlaylistResponse(BaseModel):
id: str
name: str
track_count: int
created_at: str
@router.get("/playlists/{id}", response_model=PlaylistResponse)
async def get_playlist(id: str) -> PlaylistResponse:
...
the response_model strips any extra fields from the return value — useful when your internal object has more data than the API should expose.
sources: