Pydantic — Data Validation from Type Hints
IntermediatePydantic models validate and convert external data using type annotations — the engine behind FastAPI request validation, with field constraints, custom validators, and clean JSON round-trips.
Overview
Data from outside — API bodies, form input, env vars, files — is untrusted. Pydantic turns a type-annotated class into a validating parser: wrong types are coerced when sensible ("42" → 42) or rejected with precise, field-level error messages. Version 2 is Rust-fast. This is THE library to know before FastAPI, because every FastAPI request/response model IS a Pydantic model — learn it here and the framework becomes obvious.
Models, Coercion & Errors
Declare fields with types; instantiate with untrusted data; Pydantic validates, converts, and raises ValidationError listing EVERY problem (not just the first).
from pydantic import BaseModel, EmailStr, Field, ValidationError
class SignupRequest(BaseModel):
name: str = Field(min_length=2, max_length=50)
email: EmailStr
age: int = Field(ge=16, le=100)
skills: list[str] = []
referral: str | None = None # optional
ok = SignupRequest(
name="Asha", email="asha@x.com",
age="21", # str -> int, coerced!
skills=["python"],
)
print(ok.age, type(ok.age)) # 21 <class 'int'>
print(ok.model_dump()) # dict
print(ok.model_dump_json()) # JSON string
try:
SignupRequest(name="A", email="not-an-email", age=12)
except ValidationError as e:
for err in e.errors():
print(err["loc"], err["msg"])
# ('name',) String should have at least 2 characters
# ('email',) value is not a valid email address
# ('age',) Input should be greater than or equal to 16Custom Validators & Nested Models
field_validator adds per-field rules; model_validator checks cross-field logic. Models nest naturally — a JSON tree validates in one call.
from pydantic import BaseModel, field_validator, model_validator
class Address(BaseModel):
city: str
pincode: str
@field_validator("pincode")
@classmethod
def valid_pin(cls, v):
if len(v) != 6 or not v.isdigit():
raise ValueError("pincode must be 6 digits")
return v
class Student(BaseModel):
name: str
cgpa: float
backlogs: int = 0
address: Address # nested model!
@model_validator(mode="after")
def placement_rule(self):
if self.cgpa < 6.0 and self.backlogs > 2:
raise ValueError("not eligible: low cgpa AND backlogs")
return self
raw = { # e.g. json from an API
"name": "Ravi", "cgpa": 8.2,
"address": {"city": "Pune", "pincode": "411001"},
}
s = Student(**raw) # whole tree validated
print(s.address.city) # Pune
# settings from environment — pydantic-settings package:
# class Settings(BaseSettings): db_url: str; debug: bool = FalseKey Points to Remember
- 1Type hints become runtime validation; sensible coercion ("42" → 42), precise errors
- 2Field(ge=, le=, min_length=...) for constraints; EmailStr and friends for formats
- 3field_validator for one field, model_validator for cross-field rules
- 4model_dump()/model_dump_json() serialize; nested models validate whole JSON trees
Interview Questions
Sign in to ask AriaWhat does Pydantic add over dataclasses? When is each appropriate?
How does FastAPI use Pydantic models under the hood?
Implement a cross-field validation rule (e.g. end_date after start_date).
Ask Aria about Pydantic — Data Validation from Type Hints
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.