Cheatsheet for Field() and constraints.

Common Field args

from pydantic import Field

class M(BaseModel):
    name: str = Field(
        ...,                                # required (Ellipsis)
        title="Name",
        description="User's full name",
        examples=["Alice"],
        min_length=1, max_length=120,
        pattern=r"^[A-Za-z ]+$",
    )
    age: int = Field(default=18, ge=0, le=150, multiple_of=1)
    bio: str | None = Field(default=None, max_length=1000)
    tags: list[str] = Field(default_factory=list, max_length=10)
    secret: str = Field(..., exclude=True)   # never serialized

Default vs default_factory

# BAD: shared mutable
tags: list[str] = []

# GOOD: per-instance
tags: list[str] = Field(default_factory=list)
created: datetime = Field(default_factory=datetime.utcnow)

Aliases

class User(BaseModel):
    full_name: str = Field(alias="fullName")
    model_config = {"populate_by_name": True}

# Accept JSON {"fullName": ...} OR {"full_name": ...}

# Separate validation / serialization aliases
class User(BaseModel):
    user_id: int = Field(validation_alias="id", serialization_alias="userId")

AliasChoices / AliasPath

from pydantic import AliasChoices, AliasPath

# Multiple alias options
name: str = Field(validation_alias=AliasChoices("name", "fullName", "full_name"))

# Nested path
user_id: int = Field(validation_alias=AliasPath("data", "user", "id"))
# accepts {"data": {"user": {"id": 42}}}

Constraints by type

String

name: str = Field(..., min_length=1, max_length=120, pattern=r"^[a-z]+$")

Numeric

age: int = Field(..., gt=0, ge=1, lt=150, le=149, multiple_of=1)

Collection

tags: list[str] = Field(default_factory=list, min_length=1, max_length=10)

Annotated types (DRY)

from typing import Annotated
from pydantic import StringConstraints

Username = Annotated[str, StringConstraints(
    min_length=3, max_length=32,
    pattern=r"^[a-z0-9_]+$",
    strip_whitespace=True,
)]

class User(BaseModel):
    username: Username

Reuse across models.

Documentation in OpenAPI

class User(BaseModel):
    email: EmailStr = Field(..., description="Email address", examples=["[email protected]"])
    age: int = Field(..., ge=0, examples=[25, 30, 45])
    
    model_config = {
        "json_schema_extra": {
            "examples": [
                {"email": "[email protected]", "age": 30},
            ]
        }
    }

Read-only / write-only

class User(BaseModel):
    id: int = Field(..., exclude=True)              # never out
    password: str = Field(..., init=False)          # not in __init__ (advanced)

For API: use separate Read/Write models.

SecretStr / SecretBytes

from pydantic import SecretStr

class Config(BaseModel):
    api_key: SecretStr

c = Config(api_key="abc")
print(c)                            # api_key=SecretStr('**********')
print(c.api_key.get_secret_value()) # "abc"

Prevents accidental logging.

Json type

from pydantic import Json

class M(BaseModel):
    payload: Json[dict]                  # accepts JSON string; parses; validates as dict

File types

from pydantic import FilePath, DirectoryPath, NewPath

class Settings(BaseModel):
    config_file: FilePath               # must exist
    output_dir: DirectoryPath           # must exist
    log_file: NewPath                   # must NOT exist

URL types

from pydantic import HttpUrl, AnyUrl, PostgresDsn

class Config(BaseModel):
    base_url: HttpUrl
    db_url: PostgresDsn

Datetime parsing

from datetime import datetime, date, time
from pydantic import AwareDatetime, NaiveDatetime

class Event(BaseModel):
    when: AwareDatetime                 # timezone-aware required
    when_naive: NaiveDatetime           # timezone-naive
    on: date
    at: time

Common mistakes

  • Field(default=[]) — shared mutable; use default_factory.
  • Forgetting populate_by_name when using aliases.
  • Putting validators inside Field — use field_validator instead.
  • Strict mode globally — query params arrive as strings.

Read this next

If you want my Annotated-types library, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .