field_validator kiểm tra một field, model_validator kiểm tra quan hệ giữa nhiều field — ví dụ end_date phải sau start_date, hay "phải có ít nhất một trong hai số điện thoại".
mode quyết định thời điểm chạy so với bước ép kiểu của Pydantic:
- mode='before': chạy trước khi ép kiểu, nhận dữ liệu thô. Dùng để chuẩn hoá đầu vào (cắt khoảng trắng, tách chuỗi thành list, đổi chuỗi rỗng thành None). Giá trị vào chưa được đảm bảo đúng kiểu.
- mode='after' (mặc định): chạy sau khi ép kiểu và validate xong, nên giá trị đã đúng kiểu khai báo. Dùng cho luật nghiệp vụ.
from pydantic import BaseModel, field_validator, model_validator
class Booking(BaseModel):
email: str
start_date: date
end_date: date
@field_validator("email", mode="before")
@classmethod
def normalize_email(cls, v: str) -> str:
return v.strip().lower()
@model_validator(mode="after")
def check_range(self) -> "Booking":
if self.end_date <= self.start_date:
raise ValueError("end_date must be after start_date")
return selfHai lưu ý: model_validator(mode='after') nhận chính instance (self) và phải trả về nó; còn mode='before' nhận dict dữ liệu thô.
Trong validator nên raise ValueError — FastAPI sẽ chuyển thành response 422 chuẩn, không cần tự ném HTTPException.