0
0
FastapiHow-ToBeginner · 4 min read

How to Use model_validator in Pydantic with FastAPI

Use @model_validator decorator inside a Pydantic model to add custom validation logic that runs on the whole model. In FastAPI, define this inside your request or response model to validate or transform data after standard field validation.
📐

Syntax

The @model_validator decorator is applied to a class method inside a Pydantic model. This method receives the entire model data as input and returns the validated or modified data.

Use mode='before' to validate before field parsing, or mode='after' to validate after fields are parsed.

python
from pydantic import BaseModel, model_validator

class MyModel(BaseModel):
    name: str
    age: int

    @model_validator(mode='after')
    def check_age(cls, values):
        if values.age < 18:
            raise ValueError('Age must be at least 18')
        return values
💻

Example

This example shows a FastAPI app using a Pydantic model with @model_validator to ensure the age is at least 18. If validation fails, FastAPI returns a 422 error.

python
from fastapi import FastAPI
from pydantic import BaseModel, model_validator

app = FastAPI()

class User(BaseModel):
    name: str
    age: int

    @model_validator(mode='after')
    def validate_age(cls, values):
        if values.age < 18:
            raise ValueError('User must be at least 18 years old')
        return values

@app.post('/users/')
async def create_user(user: User):
    return {'message': f'User {user.name} is valid and created.'}
Output
POST /users/ with {"name": "Alice", "age": 20} returns {"message": "User Alice is valid and created."} POST /users/ with {"name": "Bob", "age": 16} returns 422 Unprocessable Entity with validation error "User must be at least 18 years old"
⚠️

Common Pitfalls

  • Using @model_validator without specifying mode defaults to after, which runs after field parsing.
  • Raising generic exceptions instead of ValueError or TypeError may not produce clear validation errors.
  • Not returning the modified or original values from the validator method will cause errors.
  • Trying to mutate the model instance directly instead of returning new values causes unexpected behavior.
python
from pydantic import BaseModel, model_validator

class WrongModel(BaseModel):
    age: int

    @model_validator()
    def bad_validator(cls, values):
        if values.age < 0:
            # Wrong: raising generic Exception
            raise Exception('Age cannot be negative')
        # Wrong: not returning values

class CorrectModel(BaseModel):
    age: int

    @model_validator(mode='after')
    def good_validator(cls, values):
        if values.age < 0:
            raise ValueError('Age cannot be negative')
        return values
📊

Quick Reference

model_validator decorator usage:

  • @model_validator(mode='before'): Validate raw input data before field parsing.
  • @model_validator(mode='after'): Validate parsed model data after field parsing.
  • Validator method must be a classmethod receiving cls and values.
  • Always return the validated or modified values.
  • Raise ValueError or TypeError for validation errors.

Key Takeaways

Use @model_validator inside Pydantic models to add custom validation logic for the whole model.
Specify mode='before' or mode='after' to control when validation runs relative to field parsing.
Always return the validated data from the validator method to avoid errors.
Raise ValueError or TypeError for clear validation error messages in FastAPI.
In FastAPI, model_validator helps enforce complex rules beyond simple field types.