在 pydantic 设置管理中使用 Class 作为 Filed 属性

Use Class as a Filed attribute in pydantic settings management

我正在使用 Pydantic 进行设置管理,现在我遇到了一个问题。

假设我对多个环境有不同的设置 class。现在我想使用 class 作为不同设置环境的字段属性,并在测试期间更改它们。问题是我能够获取 class,但没有在执行期间明确设置它。这是一个简短的例子:

In [96]: from typing import TypeVar

In [97]: UserSchemaType = TypeVar("UserSchemaType", bound=BaseModel)

In [98]: from pydantic import BaseModel

In [99]: class User(BaseModel):
    ...:     id: str
    ...: 

In [100]: class CustomUser(BaseModel):
     ...:     id: str
     ...:     first_name: str
     ...:     last_name: str
     ...: 

In [101]: class AppSettings(BaseSettings):
     ...:     # some settings
     ...:     foo: str = 'foo'
     ...: 
     ...:     user_class: UserSchemaType = User
     ...: 

In [102]: class TestAppSettings(AppSettings):
     ...:     # some settings
     ...:     pass
     ...: 

In [103]: test_app_settings = TestAppSettings()

In [104]: test_app_settings.dict()
Out[104]: {'foo': 'foo'}

In [105]: test_app_settings.user_class
Out[105]: __main__.User

In [106]: test_app_settings.user_class = CustomUser
ValueError: "TestAppSettings" object has no field "user_class"

AppSettings.user_class 输入不正确。

注释 user_class: UserSchemaType 声明 user_class 应该是 BaseModel 的实例,例如 user_class: UserSchemaType = User(...).

但是,您分配的是类型,而不是实例:user_class: UserSchemaType = User

正确的注释是 user_class: type[UserSchemaType] 或者,根据您的 python 版本,您需要使用 from typing import Type,然后是 user_class: Type[UserSchemaType] = User

如果您在使用不正确的类型注释时检查 test_app_settings.__fields__,您会发现 user_class 不存在。 Pydantic 覆盖 __setattr__,默认情况下它会检查属性名称是否在 __fields__ 中,如果没有找到,它会抛出您遇到的错误。

我很快就找到了 __getattr__ 的实现,似乎 pydantic 没有重新实现它,所以你的属性访问检查(test_app_settings.user_class 在你的例子中输入 105)是受制于正常的 python MRO 属性查找,这就是它在那里找到它的原因。

顺便说一句,在您的示例中使用 TypeVar 并没有真正让您受益,因为 class 不是通用的。您可以轻松地使用 user_class: type[BaseModel] = User.