【问题标题】:What does Pydantic ORM mode exactly do?Pydantic ORM 模式究竟做了什么?
【发布时间】:2023-01-24 06:09:05
【问题描述】:

根据docs,需要 Pydantic“ORM 模式”(通过 Config 中的 orm_mode = True 启用)来启用 from_orm 方法,以便通过从另一个类实例读取属性来创建模型实例。如果未启用 ORM 模式,from_orm 方法会引发异常。

我的疑问是:

  1. 启用 ORM 模式是否有任何其他影响(在功能、性能等方面)?
  2. 如果不是,为什么它是一个可选功能?

【问题讨论】:

  • Pydantic 开发社区似乎更适合解决这个问题。此处提供的答案很可能是推测和/或意见。
  • @itprorh66 虽然我同意你对第二问题,我仍然认为第一的问题可以得到回答并为他人提供价值。这里的问题是(通常是)OP 一次问了多个问题。在我看来,关闭它仍然是没有根据的。也许 OP 可以简单地将第二部分改写为观察,以更加关注第一部分。

标签: python pydantic


【解决方案1】:

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

从版本 1.10.4 开始,有只有两个地方(除了插件),orm_mode 发挥作用。


BaseModel.from_orm

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


BaseModel.validate

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

如果 orm_modeTrue 并且验证器遇到的是不是模型的一个实例和不是一个字典,它假设它是一个可以传递给上述from_orm方法和calls that的对象,而不是尝试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())

输出是{"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())

新的输出:

called `Foo.validate`
{"f": {"x": 1}}

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

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

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


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

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

BaseModel 的其他功能不会以我所见的任何方式受到该配置设置的影响(性能方面)。


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

【讨论】:

    猜你喜欢
    • 2015-07-08
    • 2012-07-23
    • 2016-09-10
    • 2023-03-15
    • 2012-10-17
    • 2021-06-04
    • 1970-01-01
    • 2018-07-30
    • 2019-10-06
    相关资源
    最近更新 更多