Pydantic缺失目标字段时如何触发校验器 从非模型字段取值?
问题原因分析
- 你的代码触发报错的核心原因有三点:
- 你的Pydantic模型未声明
src字段,Pydantic默认会直接丢弃输入数据中未在模型中定义的字段,运行foo的validator时values参数根本取不到src的值 - 单字段validator的
values参数仅包含当前字段之前、已经完成验证的字段的值,即使你声明了src,如果src的定义顺序在foo之后,也无法在foo的validator中拿到src的取值 - 输入数据中没有传入
foo字段的初始值,在validator无法正常推导返回值的情况下,Pydantic会判定该必填字段缺失
- 你的Pydantic模型未声明
可行解决方案
方案1:声明隐藏的src字段(无需root validator)
你可以将src声明为模型的字段,通过exclude=True配置让它在序列化导出时自动隐藏,不影响输出结构,同时调整字段顺序让src在foo之前完成验证:
from pydantic import BaseModel, validator, Field class Model(BaseModel): # 声明src字段,序列化时自动排除,不会出现在模型输出中 src: dict = Field(..., exclude=True) foo: int @validator('foo', always=True, check_fields=False) def convert_foo(cls, v, values): # 此时values中已经包含验证完成的src值 src_val = values['src'] return [*src_val.keys()][0] m = Model.parse_obj({'src': {1: 2}}) print(m.foo) # 输出 1 print(m.dict()) # 输出 {'foo': 1},不会包含src字段
方案2:使用pre根验证器(更适合多字段推导场景)
如果你的推导逻辑涉及多个字段、或者不想额外声明不需要的隐藏字段,可以用前置根验证器直接处理原始输入,提前为foo赋值:
from pydantic import BaseModel, root_validator class Model(BaseModel): foo: int @root_validator(pre=True) def fill_foo_from_src(cls, values): src = values.get('src') if isinstance(src, dict) and src: values['foo'] = [*src.keys()][0] return values m = Model.parse_obj({'src': {1: 2}}) print(m.foo) # 输出 1
方案选择说明
- 不是只有root validator这一种解决方案
- 单字段推导、推导逻辑仅和某一个额外输入字段相关的场景,更推荐用方案1,逻辑拆分更清晰,验证报错定位更准确
- 多字段批量推导、输入结构和模型结构差异较大的场景,更推荐用方案2,灵活度更高
内容的提问来源于stack exchange,提问作者Anton Ovsyannikov
相关产品推荐
相关产品推荐

