External JSON rarely matches Python naming, and outputs often need derived or reformatted values.
Aliases decouple the attribute name from the external key.
Field(alias="userId")sets the name for both validation and serialization (when you dump withby_alias=True).validation_aliasandserialization_aliasset each direction separately.validation_alias=AliasChoices("user_id", "userId")accepts either spelling, andAliasPath("data", 0, "id")digs into nested input.model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)(withto_camelfrompydantic.alias_generators) gives every field a camelCase alias while still allowing snake_case input.
By default, input must use the alias once one is set, and dumps use field names unless you pass by_alias=True (or configure serialize_by_alias=True).
Computed fields are properties included in dumps and JSON Schema:
@computed_field
@property
def total(self) -> float: ...They are read-only and recomputed on each access; annotate the return type so the schema knows it.
Custom serializers change how a field is written without changing how it is stored. @field_serializer("amount") returns the output value; for example, a Decimal as a string to avoid float rounding. when_used="json" limits it to JSON mode. @model_serializer takes over the whole model's output.
Keep these output concerns on the model rather than post-processing dicts in every endpoint: one definition, consistent everywhere.
Example
from decimal import Decimal
from pydantic import BaseModel, ConfigDict, computed_field, field_serializer
from pydantic.alias_generators import to_camel
class Invoice(BaseModel):
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
invoice_id: int
unit_price: Decimal
quantity: int
@computed_field
@property
def total_price(self) -> Decimal:
return self.unit_price * self.quantity
@field_serializer("unit_price", "total_price", when_used="json")
def money(self, v: Decimal) -> str:
return f"{v:.2f}"
inv = Invoice.model_validate({"invoiceId": 9, "unitPrice": "2.5", "quantity": 3})
print(inv.invoice_id, inv.total_price) # 9 7.5
print(inv.model_dump_json(by_alias=True))
# {"invoiceId":9,"unitPrice":"2.50","quantity":3,"totalPrice":"7.50"}
print(Invoice(invoice_id=1, unit_price=1, quantity=1).invoice_id) # 1 (by name)Remember
- alias, validation_alias and serialization_alias map external names
- alias_generator=to_camel plus populate_by_name handles camelCase APIs
- @computed_field exposes derived values in dumps and schemas
- @field_serializer customizes output without changing stored values
Watch out for
- Expecting dumps to use aliases by default; pass by_alias=True or set serialize_by_alias.