Skip to content

第五章:验证器:自定义校验逻辑 ​

内置约束不够用?自己写校验函数。这是 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 v

5.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% 的"为什么我的验证器拿到的值不对"都能想明白。