创建pydantic.使用外部类或字典定义BaseModel



我有一个简单类的(动态)定义,如下所示:

class Simple:
val: int = 1

我打算用这个定义来构建一个pydantic.BaseModel,所以它可以从Simple类定义;基本上是这样做的,但通过type,在元类结构下,Simple类是从。

from pydantic import BaseModel
class SimpleModel(Simple, BaseModel):
pass
# Actual ways tried:
SimpleModel = type('SimpleModel', (Simple, BaseModel), {})
# or
SimpleModel = type('SimpleModel', (BaseModel, ), Simple.__annotations__)

然而,这种方法并没有返回一个带有Simple类参数的模型类。

我知道BaseModel已经在底层使用了一个相当复杂的元类,然而,我的预期实现也是在元类下,我打算动态地Simple类从pydantic转移到BaseModel

请多多指教。

我首先设法得到这个工作,将我的Simple类转换为pydantic的数据类,然后从中获得pydantic模型。

我不是pydantic方面的专家,所以我不介意你对这个方法的看法。

from pydantic.dataclasses import dataclass
SimpleModel = dataclass(Simple).__pydantic_model__

然而,我发现的麻烦(与@jsbueno提供的答案相同),当直接使用BaseModel声明pathlib.Path(作为示例)的数据类型注释时,所提供的字符串值被强制转换为注释数据类型。但是使用我的或@jsbueno方法,数据类型保持原始(没有强制转换)。

您可以简单地调用type,传递由SimpleModel__dict__属性组成的字典-该字典将包含您的文件的默认值和__annotations__属性,这些信息足以让Pydantic完成它的事情。

我只是会采取额外的步骤删除__weakref__属性,该属性是在普通的"SimpleModel"中默认创建的。在此之前-避免它指向错误的类。

from pydantic import BaseModel
class Simple:
val: int = 1
new_namespace = dict(Simple.__dict__)  # copies the class dictproxy into a plain dictionary
del new_namespace["__weakref__"]
SimpleModel = type("SimpleModel", (BaseModel,), new_namespace)

In [58]: SimpleModel.schema()                                                                                                                                               
Out[58]: 
{'title': 'Simple',
'type': 'object',
'properties': {'one_val': {'title': 'One Val',
'default': 1,
'type': 'integer'}}}

可以工作-但是由于Pydantic很复杂,为了使其更适合未来,最好使用Pydantic的元类提供的命名空间对象而不是普通的字典-正式的方法是使用types模型中的辅助函数:

import types
from pydantic import BaseModel
class Simple:
val: int = 1
SimpleModel = types.new_class(
"SimpleModel",
(BaseModel,),
exec_body=lambda ns:ns.update(
{key: val for key, val in Simple.__dict__.items()
if not key.startswith("_")}
)
) 

new_type调用计算适当的元类,并将正确的命名空间对象传递给exec_body参数中的回调。在这里,我们只需用动态类中字典的内容填充它。

这里,我选择更新名称空间并过滤所有的"_"值在一行中,但是您可以定义函数传递给"exec_body"作为一个完整的多行功能,更仔细地过滤您想要的内容。