使用非关键字参数初始化FastAPI BaseModel(也称为*args)



我有一个FastApi项目,我试图使用python元组初始化,

from pydantic import BaseModel
class Item(BaseModel):
name: str = ""
surname: str = ""
data = ("jhon", "dhon")
Item(*data)

输出以下错误

TypeError: __init__() takes 1 positional argument but 3 were given

是否有从元组初始化BaseModel的方法?

不能,Pydantic模型只能用关键字参数初始化。如果必须从位置参数初始化它,可以查看模式:

>>> Item(**dict(zip(Item.schema()["properties"], data)))
Item(name='jhon', surname='dhon')

我写了一个辅助函数,可以从元组中加载数据,但是

def fill_model(model: BaseModel, columns: List, row: Tuple) -> BaseModel:
base_model = model()
model_keys = base_model.dict().keys()
fields_count = len(model_keys)
if fields_count != len(columns):
raise ValueError("Columns length doesn't match fields count")
if not set(columns).issubset(model_keys):
raise ValueError("Columns doesn't match model fields")
if fields_count != len(row):
raise ValueError("Data length doesn't match fields count")
return model(**{k: v for k, v in zip(columns, row)})

您还可以使用pydantics BaseModel parse_obj函数:Item.parse_obj(some_dict)。但是,您需要编写一个包装器函数/使用类中的键。

from pydantic import BaseModel
class Item(BaseModel):
name: str = ""
surname: str = ""    
data = ("jhon", "dhon")
fields = Item.__fields__.keys()
zipped_dict = dict(zip(fields, data))
item = Item.parse_obj(zipped_dict)

这样做的好处是,考虑到元组总是包含正确的数据,在Item类中有更多的条目是很容易处理的。

此解决方案将Item类的属性与数据元组中的条目压缩。将其转换为字典,可以使用pydantics的parse_obj函数。

一种选择是覆盖__init__,设置位置参数并将它们作为关键字参数传递给BaseModel的init:

from pydantic import BaseModel
class Item(BaseModel):
name: str = ""
surname: str = ""
def __init__(self, name, surname):
super().__init__(name=name, surname=surname)
data = ("jhon", "dhon")
Item(*data)

输出:

Item(name='jhon', surname='dhon')

如果您有更多的字段,并希望有这种方法的更动态的版本,我添加了更多的例子来回答类似的问题:https://stackoverflow.com/a/72657947/13696660

最新更新