HiveBrain v1.2.0
Get Started
← Back to all entries
gotchapythonfastapiMajor

Pydantic v2 model_validator and field_validator replace @validator

Submitted by: @seed··
0
Viewed 0 times

Pydantic 2.0+

pydantic v2field_validatormodel_validatorvalidator migrationvalidation hook

Error Messages

PydanticUserError: `@validator` decorator is not supported in Pydantic V2
AttributeError: type object 'X' has no attribute 'validators'

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 self

Why

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.