根据文档,需要Pydantic“ORM模式”(在Config中使用orm_mode = True启用)来启用from_orm方法,以便通过从另一个类示例阅读属性来创建模型示例。如果未启用ORM模式,则from_orm方法将引发异常。我的疑虑是:1.启用ORM模式是否有任何其他影响(功能、性能等方面)?1.如果不是,为什么它是一个选择加入的功能?
Config
orm_mode = True
from_orm
py49o6xq1#
幸运的是,至少第一个问题可以相当容易地回答。从1.10.4版本开始,只有两个地方(插件除外)可以使用orm_mode。
1.10.4
orm_mode
BaseModel.from_orm
这基本上是一个替代构造函数。它放弃了常规的__init__方法,而采用了稍微不同的设置。不确定为什么要这样设计。但是必须设置orm_mode标志,这样该方法才不会引发错误。很简单。我在这里没有看到隐藏的惊喜。
__init__
BaseModel.validate
此方法是BaseModel类型的默认验证器。如果没有orm_mode标志,则验证器期望的值为1)特定模型的示例,2)可以解包到该模型的构造函数中的字典,或者3)可以 * 强制 * 到字典,然后解包到该模型的构造函数中的内容。如果orm_mode是True,并且验证器遇到的东西 * 不是 * 模型的示例,* 也不是 * 字典,那么它会假设它是一个可以传递给前面提到的from_orm方法的对象,并调用它,而不是尝试dict强制。请注意,在初始化过程中不调用此方法,如果将某个值赋给非BaseModel的任何类型的模型字段,则不调用此方法。(并且用作数据输入的对象也是嵌套的),也就是说,一个模型有一个用另一个模型注解的字段,只有这样,外部模型才会调用内部模型的validate方法。请考虑以下几点:
BaseModel
True
dict
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没有被调用。现在我们对此进行一些扩展:
{"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已经开放了一段时间,建议完全删除设置,这似乎是一种符合你的推理,它不应该是"opt-in"在任何情况下。我不知道如果塞缪尔科尔文仍然接受向后兼容的功能请求的v2。但是这个问题还没有得到很大的关注,你可能想参加那里。
print
Foo.from_orm
Bar.from_orm
parse_obj
1条答案
按热度按时间py49o6xq1#
幸运的是,至少第一个问题可以相当容易地回答。
从
1.10.4
版本开始,只有两个地方(插件除外)可以使用orm_mode
。BaseModel.from_orm
这基本上是一个替代构造函数。它放弃了常规的
__init__
方法,而采用了稍微不同的设置。不确定为什么要这样设计。但是必须设置orm_mode
标志,这样该方法才不会引发错误。很简单。我在这里没有看到隐藏的惊喜。BaseModel.validate
此方法是
BaseModel
类型的默认验证器。如果没有orm_mode
标志,则验证器期望的值为1)特定模型的示例,2)可以解包到该模型的构造函数中的字典,或者3)可以 * 强制 * 到字典,然后解包到该模型的构造函数中的内容。如果
orm_mode
是True
,并且验证器遇到的东西 * 不是 * 模型的示例,* 也不是 * 字典,那么它会假设它是一个可以传递给前面提到的from_orm
方法的对象,并调用它,而不是尝试dict
强制。请注意,在初始化过程中不调用此方法,如果将某个值赋给非
BaseModel
的任何类型的模型字段,则不调用此方法。(并且用作数据输入的对象也是嵌套的),也就是说,一个模型有一个用另一个模型注解的字段,只有这样,外部模型才会调用内部模型的validate
方法。请考虑以下几点:
输出为
{"x": 1}
,我们看到Foo.validate
没有被调用。现在我们对此进行一些扩展:
新输出:
现在验证器按预期被调用了,如果我们将类似的
print
语句注入到Foo.from_orm
中,我们将看到它也被调用了,当我们在Foo.validate
被调用之后立即调用Bar.from_orm
时。这在某些特定的情况下可能是相关的,但一般来说,我认为在验证过程中级联应用
from_orm
是有意义的,并且应该适应主要的预期用例--数据库ORM对象。如果您希望在验证过程中有不同的行为,您可以定义自己的validator方法,甚至简单地覆盖
validate
方法(取决于您的用例)。在源代码中没有
orm_mode
的其他用途,所以就功能而言就是这样。性能在IMO环境中并不重要,因为它只是一种完全不同的初始化模型示例的方法。除非你想知道首先手动将ORM对象转换为字典并将其传递给
parse_obj
或直接在其上调用from_orm
是否更快。不过你可以相当容易地对它进行基准测试。在我看来,
BaseModel
的其他功能不会受到该配置设置的任何影响(性能方面)。对于你的第二个问题,我只能猜测。所以我将避免回答。有一个issue已经开放了一段时间,建议完全删除设置,这似乎是一种符合你的推理,它不应该是"opt-in"在任何情况下。我不知道如果塞缪尔科尔文仍然接受向后兼容的功能请求的v2。但是这个问题还没有得到很大的关注,你可能想参加那里。