gotchapythonfastapiMajor
Pydantic v2 model_validator and field_validator replace @validator
Viewed 0 times
Pydantic 2.0+
pydantic v2field_validatormodel_validatorvalidator migrationvalidation hook
Error Messages
Problem
Code using Pydantic v1's @validator decorator breaks in Pydantic v2. The decorator is removed and the validation API changed significantly.
Solution
Replace @validator with @field_validator (per-field) or @model_validator (whole-model). Use mode='before' or mode='after' to control when validation runs. field_validator receives the raw value (before coercion) when mode='before'.
from pydantic import BaseModel, field_validator, model_validator
class User(BaseModel):
name: str
age: int
@field_validator('name')
@classmethod
def name_must_not_be_empty(cls, v: str) -> str:
if not v.strip():
raise ValueError('name cannot be empty')
return v.strip()
@model_validator(mode='after')
def check_age_with_name(self) -> 'User':
if self.age < 0:
raise ValueError('age cannot be negative')
return selfWhy
Pydantic v2 rewrote validation internals in Rust (via pydantic-core) for performance. The API was redesigned to be more explicit about when validation runs and whether it operates on raw or already-coerced data.
Gotchas
- @validator is removed entirely in v2 — pydantic-v1 compat shim exists but is deprecated
- field_validator must be a classmethod in v2
- mode='before' receives raw (pre-coercion) value; mode='after' receives the typed value
- model_validator(mode='before') receives a dict; mode='after' receives the model instance
- Use model_config = ConfigDict(...) instead of class Config in v2
Context
Migrating from Pydantic v1 to v2, or writing new FastAPI apps with Pydantic v2
Revisions (0)
No revisions yet.