Pydantic ORM 模式到底有什么作用?

rro*_*y86 10 python pydantic

根据文档,需要Pydantic“ORM 模式”(通过orm_mode = Truein启用)来启用该方法,以便通过从另一个类实例读取属性来创建模型实例。如果未启用 ORM 模式,该方法将引发异常。Configfrom_ormfrom_orm

我的疑问是:

  1. 启用 ORM 模式是否还有其他影响(功能、性能等)?
  2. 如果不是,为什么它是一个选择加入功能?

Dan*_*erg 5

幸运的是,至少第一个问题可以相当容易地回答。

截至 version 1.10.4,只有两个地方(除了插件)orm_mode可以发挥作用。


BaseModel.from_orm

这基本上是一个替代构造函数。它放弃了常规__init__方法,转而采用略有不同的设置。不知道为什么要这样设计。但orm_mode必须设置该标志才能使该方法不引发错误。直截了当。我在这里看不到隐藏的惊喜。


BaseModel.validate

此方法是该类型的默认验证器BaseModel。如果没有该orm_mode标志,验证器期望的值是 1) 该特定模型的实例,2) 可以解压到该模型的构造函数中的字典,或者 3) 可以强制转换字典的值,然后被解包到该模型的构造函数中。

如果orm_modeTrue并且验证器遇到的东西既不是模型的实例也不字典,它假设它是一个可以传递给上述方法的对象from_orm调用它而不是尝试dict强制。

请注意,在初始化期间不会调用此方法,并且如果将某些内容分配给任何类型的模型字段,则不会调用BaseModel该方法。仅您处理嵌套模型(并且用作数据输入的对象也是嵌套的)时,即处理具有用另一个模型注释的字段的模型时,它才发挥作用。只有这样外层模型才会调用validate内层模型的方法。

考虑以下:

from __future__ import annotations
from typing import TypeVar

from pydantic import BaseModel


M = TypeVar("M", bound=BaseModel)


class Foo(BaseModel):
    x: int

    @classmethod
    def validate(cls: type[M], value: object) -> M:
        print("called `Foo.validate`")
        return super().validate(value)

    class Config:
        orm_mode = True


class A:
    x = 1


foo = Foo.from_orm(A)
print(foo.json())
Run Code Online (Sandbox Code Playgroud)

输出是{"x": 1},我们看到它Foo.validate没有被调用。

现在我们稍微扩展一下:

...


class Bar(BaseModel):
    f: Foo

    class Config:
        orm_mode = True


class B:
    f = A


bar = Bar.from_orm(B)
print(bar.json())
Run Code Online (Sandbox Code Playgroud)

新的输出:

called `Foo.validate`
{"f": {"x": 1}}
Run Code Online (Sandbox Code Playgroud)

现在验证器已按预期被调用,如果我们要注入类似的print语句,Foo.from_orm当我们在被调用Bar.from_orm后立即调用时,我们会看到它也被调用Foo.validate

这可能与某些利基情况相关,但一般来说,我认为from_orm验证过程中的这种级联应用程序是有意义的,并且应该适应主要的预期用例——数据库 ORM 对象。

如果您希望在验证期间有不同的行为,您始终可以定义自己的验证器方法,甚至简单地覆盖该validate方法(取决于您的用例)。


源代码中没有其他用途orm_mode,所以就功能而言就是这样。

在我看来,性能在这些上下文中并不真正相关,因为它只是初始化模型实例的一种完全不同的方式。除非您想知道首先手动将 ORM 对象转换为字典并将其传递给它parse_obj或仅调用from_orm它是否更快。不过,您可以相当容易地进行基准测试。

BaseModel据我所知,该配置设置不会影响其他功能(性能方面)。


对于你的第二个问题,我只能推测。所以我不会回答。有一个问题已经开放了一段时间,建议完全删除该设置,这似乎符合您的推理,即在任何情况下都不应该“选择加入”。我不确定 Samuel Colvin 是否仍然接受 v2 的向后不兼容功能请求,但这个问题并没有引起太多关注。您可能想参加那里。