【问题标题】:How to parse list of models with Pydantic如何使用 Pydantic 解析模型列表
【发布时间】:2019-09-09 18:34:00
【问题描述】:

我使用 Pydantic 对 API 的请求和响应进行建模。

我定义了一个User 类:

from pydantic import BaseModel

class User(BaseModel):
  name: str
  age: int

我的 API 返回一个用户列表,我使用 requests 检索并转换为字典:

users = [{"name": "user1", "age": 15}, {"name": "user2", "age": 28}]

如何将此 dict 转换为 User 实例列表?

我现在的解决方案是

user_list = []
for user in users:
  user_list.append(User(**user))

【问题讨论】:

    标签: python pydantic


    【解决方案1】:

    现在可以使用parse_obj_as

    from pydantic import parse_obj_as
    
    users = [
        {"name": "user1", "age": 15}, 
        {"name": "user2", "age": 28}
    ]
    
    m = parse_obj_as(List[User], users)
    

    【讨论】:

    • 是否有逆向功能,即给定 List[User] 转换 List[dict]
    【解决方案2】:

    为了确认和扩展之前的answer,这里是pydantic-github 的“官方”答案 - 所有致谢“dmontagu”:

    在 pydantic 中执行此操作的“正确”方法是使用“自定义根目录” 类型”。您仍然需要使用容器模型:

    class UserList(BaseModel):
        __root__: List[User]
    

    但接下来会起作用:

    UserList.parse_obj([
        {'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']},
        {'id': '456', 'signup_ts': '2017-06-02 12:22', 'friends': ['you']},
    ])
    

    (并将值放在 root 属性中)。

    不幸的是,我认为没有很好的序列化支持 这还没有,所以我想当你去返回结果时,如果你想 只返回一个列表,您仍然需要返回 UserList。root

    我认为目前没有一个统一的界面可以让您获得 模型的序列化/非结构化版本,尊重 root_model,但如果这是您正在寻找的,那么它可能值得构建。

    【讨论】:

    • 如果您将.json() 用于具有自定义根类型的模型,它将以根对象为根(没有'__root__': )。
    • 除非您使用.dict(),否则它将包含__root__ 键:)
    【解决方案3】:

    你可以试试这个

    from typing import List
    from pydantic import BaseModel
    
    class User(BaseModel):
      name: str
      age: int
    
    class Users(BaseModel):
        users: List[User]
    
    users = [{"name": "user1", "age": 15}, {"name": "user2", "age": 28}]
    m = Users(users=users)
    print(m.dict())
    

    【讨论】:

    • 谢谢,但这会返回一个带有 users 属性的对象,其中包含列表。如果没有办法做到这一点,我会记住它,那就更好了!
    【解决方案4】:

    您可以考虑使用列表推导以及 dict 解包到 User 构造函数

    user_list = [
      User(**user) for user in users
    ]
    

    【讨论】:

    • 我喜欢,很干净
    • 最简单最明显的。应该被接受的答案。
    • 仅供参考,这种方法比接受的答案快大约 2x。我不知道为什么另一个被接受了,哈哈。
    【解决方案5】:

    您可以使用__root__ Pydantic 关键字:

    from typing import List
    from pydantic import BaseModel
    
    class User(BaseModel):
      name: str
      age: int
    
    class UserList(BaseModel):
      __root__: List[User]     # ⯇-- __root__
    

    构建 JSON 响应:

    user1 = {"name": "user1", "age": 15}
    user2 = {"name": "user2", "age": 28}
    
    user_list = UserList(__root__=[])
    user_list.__root__.append(User(**user1))
    user_list.__root__.append(User(**user2))
    

    您的 API Web 框架可以将 user_list json 化为 JSON 数组(在响应正文中)。

    【讨论】:

      【解决方案6】:

      如果 pydantic 版本低于 1.2 且不支持 parse_obj_as 方法,我有另一个想法来简化此代码。

      user_list = []
      for user in users:
        user_list.append(User(**user))
      

      简单的方法

      user_list = [User(**user) for user in users]
      

      【讨论】:

        【解决方案7】:

        我刚刚在我的 models.py dict 列表中设置如下:

        from django.db import models
        from pydantic import BaseModel
        
        class CustomList(BaseModel):
            data: list[dict]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-17
          • 2022-06-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-17
          • 2020-05-24
          • 1970-01-01
          相关资源
          最近更新 更多