logo

Custom Validators

Built-in validation covers types and basic constraints. For custom rules, write validators.

from pydantic import BaseModel, field_validator

class User(BaseModel):
    email: str

    @field_validator("email")
    @classmethod
    def email_must_contain_at(cls, v):
        if "@" not in v:
            raise ValueError("must contain @")
        return v

Validators run during model creation:

User(email="not-an-email")  # Error: must contain @
User(email="valid@example.com")  # Works

Validators can transform values too:

@field_validator("name")
@classmethod
def normalize_name(cls, v):
    return v.strip().title()  # "  alice  " becomes "Alice"

For validation that spans multiple fields, use model_validator:

@model_validator(mode="after")
def check_passwords_match(self):
    if self.password != self.confirm_password:
        raise ValueError("passwords don't match")
    return self

I cover custom validators in my Pydantic course.