Loading...
Loading...
Activated when the user wants to create a data model, validate data, serialize JSON, create Pydantic models, add validators, define settings, or create request/response schemas. Covers Pydantic v2 BaseModel, Field, validators, data validation, JSON schema generation, serialization, deserialization, and settings management.
npx skill4agent add ingpdw/pdw-python-dev-tool pydanticBaseModelField()from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field
class User(BaseModel):
id: int
name: str = Field(min_length=1, max_length=100, description="Full name")
email: str
age: Optional[int] = Field(default=None, ge=0, le=150)
is_active: bool = True
created_at: datetime = Field(default_factory=datetime.utcnow)Optional[T]T | NoneNoneField(default=...)Field(default_factory=callable)Field()| Parameter | Purpose |
|---|---|
| Static default value |
| Callable producing a default |
| Alternative name for parsing input |
| Human-readable title for JSON Schema |
| Field description for JSON Schema |
| Numeric constraints |
| String/collection length |
| Regex pattern for strings |
| Exclude from serialization |
| Make individual field immutable |
from pydantic import (
BaseModel,
EmailStr,
HttpUrl,
Field,
constr,
conint,
confloat,
conlist,
)
class Profile(BaseModel):
username: constr(min_length=3, max_length=30, pattern=r"^[a-zA-Z0-9_]+$")
email: EmailStr
website: HttpUrl | None = None
score: conint(ge=0, le=100) = 0
rating: confloat(ge=0.0, le=5.0) = 0.0
tags: conlist(str, min_length=1, max_length=10) = ["general"]Installto usepydantic[email].EmailStr
EmailStrHttpUrlAnyUrlIPvAnyAddressSecretStrFilePathDirectoryPathPastDatetimeFutureDatetimePositiveIntNegativeIntNonNegativeIntUUID4Json[T]Tmodel_configConfigDictfrom pydantic import BaseModel, ConfigDict
class Item(BaseModel):
model_config = ConfigDict(
str_strip_whitespace=True,
frozen=False,
from_attributes=True,
populate_by_name=True,
use_enum_values=True,
validate_default=True,
strict=False,
json_schema_extra={"examples": [{"item_name": "Widget", "price": 9.99}]},
)
item_name: str = Field(alias="itemName")
price: float| Option | Effect |
|---|---|
| Strip leading/trailing whitespace from strings |
| Make all fields immutable (model becomes hashable) |
| Allow initialization from ORM objects via attribute access |
| Accept both field name and alias during parsing |
| Store enum values instead of enum members |
| Run validators on default values |
| Disable type coercion globally |
| |
| Extend generated JSON Schema |
@field_validatorfrom pydantic import BaseModel, field_validator
class Signup(BaseModel):
username: str
password: str
@field_validator("username")
@classmethod
def username_must_be_alphanumeric(cls, v: str) -> str:
if not v.isalnum():
raise ValueError("must be alphanumeric")
return v.lower()
@field_validator("password", mode="after")
@classmethod
def password_strength(cls, v: str) -> str:
if len(v) < 8:
raise ValueError("must be at least 8 characters")
return vmode="before"mode="after"@field_validator("field_a", "field_b")@model_validatorfrom pydantic import BaseModel, model_validator
class DateRange(BaseModel):
start: datetime
end: datetime
@model_validator(mode="after")
def check_date_order(self) -> "DateRange":
if self.start >= self.end:
raise ValueError("start must be before end")
return selfmode="before"mode="after"BeforeValidatorAfterValidatorWrapValidatorfrom pydantic import BaseModel, computed_field
class Rectangle(BaseModel):
width: float
height: float
@computed_field
@property
def area(self) -> float:
return self.width * self.heightmodel_dump()user = User(id=1, name="Ada", email="ada@example.com")
data = user.model_dump() # full dict
data = user.model_dump(exclude_none=True) # drop None values
data = user.model_dump(include={"id", "name"}) # only selected fields
data = user.model_dump(exclude={"created_at"}) # exclude fields
data = user.model_dump(by_alias=True) # use alias names as keys
data = user.model_dump(mode="json") # JSON-compatible typesmodel_dump_json()json.dumps(model.model_dump())json_str = user.model_dump_json(indent=2, exclude_none=True)serialization_aliasclass ApiResponse(BaseModel):
internal_id: int = Field(serialization_alias="id")
status_code: int = Field(serialization_alias="status")from pydantic import field_serializer
class Event(BaseModel):
timestamp: datetime
@field_serializer("timestamp")
def serialize_ts(self, v: datetime, _info) -> str:
return v.isoformat()user = User.model_validate({"id": 1, "name": "Ada", "email": "ada@example.com"})user = User.model_validate_json('{"id": 1, "name": "Ada", "email": "ada@example.com"}')from_attributes=Truemodel_configclass UserRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
name: str
# sqlalchemy_user is an ORM instance
user_read = UserRead.model_validate(sqlalchemy_user)BaseSettings.envpip install pydantic-settingsfrom pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
env_prefix="APP_",
env_nested_delimiter="__",
case_sensitive=False,
)
app_name: str = "My App"
debug: bool = False
database_url: str
redis_url: str = "redis://localhost:6379"
allowed_origins: list[str] = ["http://localhost:3000"]
settings = Settings()env_prefix="APP_"database_urlAPP_DATABASE_URLenv_nested_delimiterclass DatabaseSettings(BaseModel):
host: str = "localhost"
port: int = 5432
name: str = "mydb"
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_nested_delimiter="__")
db: DatabaseSettings = DatabaseSettings()DB__HOST=prod-dbDB__PORT=5433class Settings(BaseSettings):
model_config = SettingsConfigDict(secrets_dir="/run/secrets")
db_password: strclass TimestampMixin(BaseModel):
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime | None = None
class UserCreate(TimestampMixin):
name: str
email: str
class UserUpdate(BaseModel):
name: str | None = None
email: str | None = Noneclass Address(BaseModel):
street: str
city: str
country: str = "US"
class Company(BaseModel):
name: str
address: Address
employees: list["Employee"] = []
class Employee(BaseModel):
name: str
role: str
Company.model_rebuild() # resolve forward referencesGeneric[T]from typing import Generic, TypeVar
from pydantic import BaseModel
T = TypeVar("T")
class PaginatedResponse(BaseModel, Generic[T]):
items: list[T]
total: int
page: int
per_page: int
has_next: bool
@computed_field
@property
def total_pages(self) -> int:
return (self.total + self.per_page - 1) // self.per_page
# Concrete usage
class UserList(PaginatedResponse[User]):
pass
# Or inline
response = PaginatedResponse[User].model_validate(data)schema = User.model_json_schema()json_schema_extramodel_configField()class Product(BaseModel):
model_config = ConfigDict(
json_schema_extra={
"examples": [{"name": "Widget", "price": 9.99}]
}
)
name: str
price: float = Field(json_schema_extra={"examples": [9.99, 19.99]})fastapi