第五章:验证器:自定义校验逻辑
内置约束不够用?自己写校验函数。这是 Pydantic 最核心的扩展点。
5.1 字段验证器 field_validator
python
from pydantic import BaseModel, field_validator
class User(BaseModel):
username: str
password: str
@field_validator("username")
@classmethod
def username_no_space(cls, v: str) -> str:
if " " in v:
raise ValueError("用户名不能包含空格")
return v
@field_validator("password")
@classmethod
def password_strength(cls, v: str) -> str:
if len(v) < 8:
raise ValueError("密码至少 8 位")
return v要点:
- 装饰器参数是 字段名,可以对多个字段复用:
@field_validator("a", "b") - 校验失败就
raise ValueError,Pydantic 会把它包装成漂亮的ValidationError - 返回的值会 替换原值,所以验证器也能用来做"清洗":
python
@field_validator("username")
@classmethod
def strip_username(cls, v: str) -> str:
return v.strip().lower() # 去空格、转小写5.2 模式:before / after / wrap
默认是 after(类型转换之后执行)。mode="before" 在转换 之前 执行,拿到的是原始输入:
python
@field_validator("tags", mode="before")
@classmethod
def split_tags(cls, v):
if isinstance(v, str):
return v.split(",") # 传 "a,b,c" 也能变成列表
return v5.3 模型验证器 model_validator
需要 跨字段 校验时用(比如"确认密码"要和"密码"一致):
python
from pydantic import BaseModel, model_validator
class RegisterForm(BaseModel):
password: str
confirm_password: str
@model_validator(mode="after")
def passwords_match(self):
if self.password != self.confirm_password:
raise ValueError("两次输入的密码不一致")
return self⚠️ 注意:v1 里用 @root_validator,v2 已改名为 @model_validator,且 mode="after" 时不再是 classmethod,直接操作 self。
5.4 校验顺序一览
数据进入模型时的完整流水线:
原始输入 → before 字段验证器 → 类型转换 → 内置约束(Field) → after 字段验证器 → after 模型验证器 → 实例创建记住这条线,90% 的"为什么我的验证器拿到的值不对"都能想明白。