在pydantic的数据模型校验场景中,依赖字段校验指的是一个字段的校验规则需要参考同模型中其他字段的取值,比如当字段A的取值为特定值时,字段B需要满足对应的格式要求。field_validator作为pydantic核心的校验装饰器,完全可以支持这类场景的实现。

field_validator 基本用法回顾
field_validator是pydantic.model_validator之外的字段级校验工具,主要用于对指定字段的入参进行校验,基础用法是装饰一个类方法,方法接收字段值作为参数,返回校验后的值或者抛出异常。
基础的单字段校验示例如下:
from pydantic import BaseModel, field_validator, ValidationError
class User(BaseModel):
age: int
@field_validator("age")
def check_age(cls, v):
if v < 0:
raise ValueError("年龄不能为负数")
return v
# 测试正常情况
user = User(age=18)
print(user.age) # 输出 18
# 测试异常情况
try:
User(age=-5)
except ValidationError as e:
print(e)
依赖字段校验的核心思路
field_validator本身接收的是单个字段的值,要实现依赖其他字段的校验,需要在校验方法中获取到整个模型的数据。pydantic的field_validator装饰的校验方法,除了接收字段值之外,还可以通过info参数获取到当前校验的上下文信息,其中包含已经校验过的其他字段的值。
需要注意的是,field_validator的校验顺序默认是按照字段在模型中定义的顺序执行的,因此如果要在一个字段的校验中依赖另一个字段的值,被依赖的字段需要定义在该字段之前,否则可能无法获取到对应的值。
具体实现示例
示例1:基础依赖字段校验
假设我们有个订单模型,当订单类型是"预售"时,预售发货时间必须晚于当前时间,其他订单类型不需要校验该字段。这里pre_sale_time字段的校验依赖order_type字段的值。
from pydantic import BaseModel, field_validator, ValidationError
from datetime import datetime
class Order(BaseModel):
order_type: str
pre_sale_time: datetime | None = None
@field_validator("pre_sale_time")
def check_pre_sale_time(cls, v, info):
# 从info.data中获取已经校验过的order_type字段值
order_type = info.data.get("order_type")
if order_type == "预售":
if v is None:
raise ValueError("预售订单必须填写预售发货时间")
if v < datetime.now():
raise ValueError("预售发货时间必须晚于当前时间")
return v
# 测试正常预售订单
order1 = Order(
order_type="预售",
pre_sale_time=datetime(2024, 12, 31)
)
print(order1.order_type, order1.pre_sale_time)
# 测试非预售订单,不需要填写预售时间
order2 = Order(order_type="现货")
print(order2.order_type, order2.pre_sale_time)
# 测试异常情况:预售订单未填发货时间
try:
Order(order_type="预售")
except ValidationError as e:
print(e)
示例2:多字段联动校验
再来看一个更复杂的场景,用户注册模型中,当用户选择"企业用户"类型时,必须填写企业名称,且企业名称长度不能小于4个字符,个人用户则不需要填写企业名称。
from pydantic import BaseModel, field_validator, ValidationError
class RegisterForm(BaseModel):
user_type: str
company_name: str | None = None
@field_validator("company_name")
def check_company_name(cls, v, info):
user_type = info.data.get("user_type")
if user_type == "企业用户":
if v is None or v.strip() == "":
raise ValueError("企业用户必须填写企业名称")
if len(v.strip()) < 4:
raise ValueError("企业名称长度不能小于4个字符")
else:
# 非企业用户清空企业名称字段
return None
return v.strip()
# 测试正常企业用户注册
form1 = RegisterForm(user_type="企业用户", company_name="测试科技有限公司")
print(form1.user_type, form1.company_name)
# 测试个人用户注册
form2 = RegisterForm(user_type="个人用户", company_name="随便填")
print(form2.user_type, form2.company_name) # 输出 个人用户 None
# 测试异常情况:企业用户企业名称过短
try:
RegisterForm(user_type="企业用户", company_name="测试")
except ValidationError as e:
print(e)
注意事项
- 字段定义顺序:被依赖的字段必须定义在依赖字段之前,否则info.data中可能获取不到对应的值,因为pydantic默认按字段定义顺序执行field_validator校验。
- info参数的使用:field_validator的校验方法需要显式声明
info参数才能获取到上下文数据,info是pydantic.ValidationInfo类型的实例,除了data属性外还包含其他校验上下文信息。 - 校验失败提示:可以通过抛出
ValueError自定义校验失败的提示信息,pydantic会将这些异常包装成ValidationError返回给调用方。 - 多字段校验:如果需要同时校验多个字段的依赖关系,也可以在field_validator中传入多个字段名,不过更推荐的方式是对依赖字段单独做校验,逻辑会更清晰。
总结
通过field_validator实现依赖字段校验的核心是利用info.data获取同模型中其他已校验字段的值,结合字段定义顺序保证依赖字段先被校验,就可以在单个字段的校验逻辑中完成跨字段的联动校验。这种方式不需要额外使用model_validator,逻辑更聚焦在单个字段的校验规则上,代码可读性和维护性都更好。
pydanticfield_validator依赖字段校验数据验证修改时间:2026-06-24 10:24:47