无法确定 Pydantic 模型中的字段类型是否为列表类型

rbh*_*lla 4 python python-typing pydantic

我正在尝试自动将 Pydantic 模型转换为数据库模式。为此,我递归地循环遍历 Pydantic 模型的字段以确定字段的类型。

作为一个例子,我有这个简单的模型:

from typing import List
from pydantic import BaseModel

class TestModel(BaseModel):
    tags: List[str]
Run Code Online (Sandbox Code Playgroud)

__fields__我使用此处描述的属性递归模型: https ://docs.pydantic.dev/usage/models/#model-properties

如果我这样做,type(TestModel).__fields__['tags']我会看到:

ModelField(name='tags', type=List[str], required=True)
Run Code Online (Sandbox Code Playgroud)

我想以编程方式检查该ModelField类型是否有List起源。我尝试过以下方法,但没有一个有效:

  • type(TestModel).__fields__['tags'].type_ is List[str]
  • type(TestModel).__fields__['tags'].type_ == List[str]
  • typing.get_origin(type(TestModel).__fields__['tags'].type_) is List
  • typing.get_origin(type(TestModel).__fields__['tags'].type_) == List

令人沮丧的是,这确实返回True

  • type(TestModel).__fields__['tags'].type_ is str

我确认字段是List类型的正确方法是什么?

Dan*_*erg 5

Pydantic 有场形状的概念。这些形状被编码为整数,并可作为模块中的常量使用fields。或多或少的标准类型已经被容纳在那里。如果一个字段被注释为list[T],那么shape该字段的属性将为SHAPE_LIST,并且type_将为T

type_的是所有不是 的上下文中的元素SHAPE_SINGLETON类型,即类似容器的类型。这就是为什么你得到str示例的原因。

因此,对于像 一样简单的东西list,您可以简单地根据该常量检查形状:

from pydantic import BaseModel
from pydantic.fields import SHAPE_LIST


class TestModel(BaseModel):
    tags: list[str]
    other: tuple[str]


tags_field = TestModel.__fields__["tags"]
other_field = TestModel.__fields__["other"]
assert tags_field.shape == SHAPE_LIST
assert other_field.shape != SHAPE_LIST
Run Code Online (Sandbox Code Playgroud)

如果您想更深入地了解字段的实际注释annotation,则存储在字段的属性中。这样您应该能够进行所有typing相关的分析,例如get_origin.

这意味着完成检查的另一种方法是:

from typing import get_origin

from pydantic import BaseModel


class TestModel(BaseModel):
    tags: list[str]
    other: tuple[str]


tags_field = TestModel.__fields__["tags"]
other_field = TestModel.__fields__["other"]

assert get_origin(tags_field.annotation) is list
assert get_origin(other_field.annotation) is tuple
Run Code Online (Sandbox Code Playgroud)

遗憾的是,据我所知,这些属性都没有在任何地方得到正式记录,但开源的美妙之处在于我们可以检查自己。属性和形状常量都不会以任何通常的方式被混淆、保护或设为私有,所以我假设它们是稳定的(至少在 Pydantic v2 下降之前)。