Pydantic root_validator异常行为:传入已有实例触发错误
问题原因与解决方案
核心原因
SQLModel中,当你给嵌套字段(比如B.others: List[A])传入已实例化的模型对象时,pre=True的root_validator仍然会被触发,但此时传入validator的values参数不再是创建实例时的原始字典,而是已经实例化的A对象。而你的root_validator逻辑是针对字典(比如调用items())设计的,自然会抛出AttributeError。
之所以会触发A的validator,是因为SQLModel的验证链会递归处理嵌套模型——哪怕你传入的是现成实例,它也会走一遍验证流程,而pre=True的validator是在所有字段解析前执行的,这时候还没进入“复用已有实例”的逻辑,就把实例当成了验证输入传进去了。
解决方法
在Base类的root_validator里加一个判断:如果传入的values是当前类的实例,直接返回即可,不需要执行字典相关的验证逻辑。
示例代码修改如下:
from sqlmodel import SQLModel, root_validator from typing import List class Base(SQLModel): @root_validator(pre=True) def base_validator(cls, values): # 先判断是不是当前类的实例,是就直接返回,跳过字典处理逻辑 if isinstance(values, cls): return values # 下面是你原本的验证逻辑,比如检查必填字段、处理默认值等 # 示例:确保某个字段存在(根据你的实际需求修改) # if "some_field" not in values: # values["some_field"] = "default_value" return values class A(Base): id: int name: str class B(Base): id: int others: List[A] = [] # 测试正常运行 x = A(id=1, name="test") z = B(id=2, others=[x]) print(z)
额外说明
如果你用的是SQLModel v2.x版本,官方推荐用@model_validator(mode="before")替代root_validator,逻辑是一样的:
from sqlmodel import SQLModel, model_validator class Base(SQLModel): @model_validator(mode="before") def base_validator(cls, values): if isinstance(values, cls): return values # 原验证逻辑 return values
内容的提问来源于stack exchange,提问作者ychiucco
相关产品推荐
相关产品推荐

