Pydantic Generic BaseModels 在验证 python 实例时意外失败,但在验证与字典相同的数据时成功。
Python:3.11.8 派丹蒂克:2.7.1
这是通用模型:
from typing import Generic, TypeVar
from pydantic import BaseModel
U = TypeVar("U")
class M1(BaseModel, Generic[U]):
a: list[U]
b: list[U]
class M2(BaseModel):
a: str
m1: M1[int]
它在验证原始字典时有效:
m2 = M2.model_validate(
{
"a": "s",
"m1": {
"a": [1],
"b": [2]
}
}
)
但是,当使用 python 类型时它不起作用:
m2 = M2(
a="s",
m1=M1(
a=[1],
b=[2]
)
) # fails :(
有趣的是,以下也失败了:
m2 = M2.model_validate(
dict(
a="s",
m1=M1(
a=[1],
b=[2]
)
)
)
这完全是预期的行为。由于
M1
是泛型类型,因此需要使用相应的要使用的类型进行声明。如果我复制并粘贴您的示例:
m2 = M2(
a="s",
m1=M1(
a=[1],
b=[2]
)
) # fails :(
它失败了:
ValidationError: 1 validation error for M2
m1
Input should be a valid dictionary or instance of M1[int] [type=model_type, input_value=M1(a=[1], b=[2]), input_type=M1]
For further information visit https://errors.pydantic.dev/2.7/v/model_type
这里重要的细节是“
M1[int]
的实例”。因此,当仅实例化 M1
而不声明其类型时,实例的类型为 M1
,与 M1[int]
类型不同。然而 M2
明确期望 M1[int]
,因此以下内容可以正常工作:
m2 = M2(
a="s",
m1=M1[int](
a=[1],
b=[2]
)
) # validates correctly
当你只是从字典中验证时,它工作得很好,因为 Pydantic 依赖于
M2.m1
中声明的默认类型,这又是 M1[int]
。
现在的问题是你想要实现什么样的行为。那么
M1
应该允许哪些类型呢?也许你必须使用类型的联合或类似的......
我希望这有帮助!