Day 12 · ~13m

Serialization

Converting models to dicts and JSON with model_dump(), model_dump_json(), exclude, and include.

🧑‍💻

I know how to create models from data. But how do I get data back out? Like when I need to send a response or save to a database?

👩‍🏫

Two methods: model_dump() gives you a Python dictionary, and model_dump_json() gives you a JSON string:

from pydantic import BaseModel

class User(BaseModel):
    name: str
    email: str
    age: int

user = User(name="Alice", email="alice@test.com", age=30)

# To dictionary
d = user.model_dump()
print(d)  # {'name': 'Alice', 'email': 'alice@test.com', 'age': 30}

# To JSON string
j = user.model_dump_json()
print(j)  # '{"name":"Alice","email":"alice@test.com","age":30}'
🧑‍💻

What if I don't want all the fields in the output? Like I want to exclude the password field from an API response?

👩‍🏫

Use exclude or include to control which fields appear:

class UserDB(BaseModel):
    id: int
    name: str
    email: str
    password_hash: str

user = UserDB(id=1, name="Alice", email="alice@test.com", password_hash="abc123")

# Exclude specific fields
public = user.model_dump(exclude={"password_hash"})
print(public)  # {'id': 1, 'name': 'Alice', 'email': 'alice@test.com'}

# Or include only specific fields
brief = user.model_dump(include={"name", "email"})
print(brief)  # {'name': 'Alice', 'email': 'alice@test.com'}
🧑‍💻

Does this work with nested models too? Can I exclude a field from a nested object?

👩‍🏫

Yes. Use a dictionary to target nested fields:

class Address(BaseModel):
    street: str
    city: str
    zip_code: str

class Customer(BaseModel):
    name: str
    address: Address

customer = Customer(
    name="Alice",
    address={"street": "123 Main", "city": "Portland", "zip_code": "97201"}
)

# Exclude zip_code from the nested address
result = customer.model_dump(exclude={"address": {"zip_code"}})
print(result)
# {'name': 'Alice', 'address': {'street': '123 Main', 'city': 'Portland'}}
🧑‍💻

What about controlling the output format? Like using aliases in the output instead of field names?

👩‍🏫

Pass by_alias=True to use aliases in the output:

from pydantic import Field

class ApiResponse(BaseModel):
    status_code: int = Field(alias="statusCode")
    message: str

resp = ApiResponse(statusCode=200, message="OK")

# Default: uses field names
print(resp.model_dump())  # {'status_code': 200, 'message': 'OK'}

# With aliases
print(resp.model_dump(by_alias=True))  # {'statusCode': 200, 'message': 'OK'}

This is the round-trip pattern: data comes in with camelCase aliases, your Python code uses snake_case, and when you serialize back out you switch to aliases again. Clean on both sides.

🧑‍💻

Is there a way to skip fields that have their default value? Like only include fields that were actually provided?

👩‍🏫

Use exclude_defaults=True or exclude_unset=True:

class Settings(BaseModel):
    theme: str = "light"
    font_size: int = 14
    language: str = "en"

s = Settings(font_size=18)
print(s.model_dump(exclude_unset=True))  # {'font_size': 18}

exclude_unset=True only includes fields that were explicitly provided. exclude_defaults=True excludes any field whose value equals the default. Both are useful for PATCH-style updates.

Practice your skills

Sign up to write and run code in this lesson.

Already have an account? Sign in