Pydantic嵌套模型验证异常:传入MyModel实例触发校验错误
问题原因与解决方案(Pydantic 1.10 + Python 3.7)
问题原因
当把已实例化的MyModel对象传入嵌套模型UserSettings时,Pydantic会对传入的MyModel实例执行重新验证流程:它会先将实例转换为字典,再基于字典重新构建MyModel对象。此时items字段的校验器被触发,但items中的元素已经是普通字典(而非SomeModel/SomeOtherModel实例),导致原校验逻辑中isinstance(v, SomeModel)全部返回False,最终触发ValueError。
单独实例化MyModel时正常,是因为此时items中的元素直接是模型实例,isinstance判断可以正确识别类型。
解决方案
针对Pydantic 1.10版本,修改MyModel的items字段校验逻辑,同时兼容模型实例和字典两种输入场景:
from pydantic import BaseModel, validator, ValidationError from typing import List, Union class SomeModel(BaseModel): name: str class SomeOtherModel(BaseModel): name: int class MyModel(BaseModel): items: List[Union[SomeModel, SomeOtherModel]] @validator("items", always=True) def validate(cls, value): has_valid_some_model = False for item in value: # 直接判断是否为SomeModel实例 if isinstance(item, SomeModel): has_valid_some_model = True break # 若为字典,尝试解析为SomeModel,成功则判定为有效类型 try: SomeModel.parse_obj(item) has_valid_some_model = True break except ValidationError: continue if not has_valid_some_model: raise ValueError("we need at least one SomeModel") return value # 嵌套模型定义不变 class ComposerModels(BaseModel): user: List[MyModel] = [] system: List[MyModel] = [] class ComposerSettings(BaseModel): models: ComposerModels class UserSettings(BaseModel): composer: ComposerSettings # 测试代码可正常运行 my_model = MyModel(items=[SomeModel(name="a"), SomeOtherModel(name=1)]) user_settings = UserSettings( composer=ComposerSettings( models=ComposerModels( user=[my_model] ) ) )
方案说明
- 校验逻辑同时处理两种输入:直接传入的
SomeModel实例,以及Pydantic重新验证时传入的字典对象 - 通过
SomeModel.parse_obj(item)判断字典是否符合SomeModel的结构,确保类型校验的准确性 - 保留了原需求:
items列表必须包含至少一个有效SomeModel类型的元素
内容的提问来源于stack exchange,提问作者Edward Spencer
相关产品推荐
相关产品推荐

