【问题标题】:Initialize FastAPI BaseModel using non keywords arguments (a.k.a *args)使用非关键字参数(a.k.a *args)初始化 FastAPI BaseModel
【发布时间】:2022-06-17 18:06:56
【问题描述】:

我有一个 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

【问题讨论】:

    标签: python-3.x fastapi pydantic


    【解决方案1】:

    不,Pydantic 模型只能使用关键字参数进行初始化。如果您绝对必须从位置参数初始化它,您可以查看架构:

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

    【讨论】:

      【解决方案2】:

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

      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)})
      

      【讨论】:

      • 请注意,如果您的模型发生变化,这将/可能以神秘的方式破坏。至少你应该给出一个index => field 映射。
      • 是的,你是对的,但我对我的元组的假设总是正确的。
      • 我说的是模型 - 如果你引入一个新字段(我不确定 pydantic 的 dict() 方法中的字段顺序是否保证) 在您的模型中 - 特别是在您现有的字段之间,例如通过添加一个 id 字段或类似的东西),keys 视图内部的排序将发生变化。如果您至少提供映射到数据元组中索引的字段名称元组,那么您将获得更少容易出错的代码(所以(model, data, mapping),其中映射类似于(key1, key2, key3)。然后相同的元组将在至少总是匹配正确的字段
      • 谢谢你的提示,我对辅助函数做了修改
      【解决方案3】:

      您还可以使用 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 类的属性与数据元组中的条目一起压缩。把这个转成dict,就可以用pydantics的parse_obj函数了。

      【讨论】:

        【解决方案4】:

        一个选项就是覆盖__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')
        

        【讨论】:

          猜你喜欢
          • 2015-09-06
          • 2017-05-26
          • 2010-10-23
          • 2018-03-03
          • 1970-01-01
          • 1970-01-01
          • 2017-10-29
          • 2018-02-19
          • 1970-01-01
          相关资源
          最近更新 更多