Как разобрать список моделей с Pydantic

Я использую 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}]

Как я могу преобразовать этот дикт в список User случаи?

Мое решение сейчас

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

9 ответов

Теперь это возможно с помощью 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)

Чтобы подтвердить и расширить предыдущий ответ, вот "официальный" ответ на pydantic-github - Все кредиты на "dmontagu":

"Правильный" способ сделать это в pydantic - использовать "Custom Root Types". Вам по-прежнему нужно использовать модель контейнера:

class UserList(BaseModel):
    __root__: List[User]
but then the following will work:

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']},
])

(и поместит значения в корневое свойство).

К сожалению, я думаю, что для этого пока нет хорошей поддержки сериализации, поэтому я думаю, что когда вы собираетесь вернуть результаты, если вы хотите вернуть только список, вам все равно нужно будет вернуть UserList.корень.

Я не думаю, что в настоящее время существует унифицированный интерфейс, который дает вам сериализованную / неструктурированную версию модели, которая уважает root_model, но если это то, что вы ищете, возможно, стоит создать.

Вы можете попробовать это

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

Вы можете использовать понимание списка вместе с распаковкой dict в User конструктор

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

Вы можете использовать __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 может jsonify user_list для возврата в виде массива JSON (в теле ответа).

Пидантик V2

Для адаптерного подхода см. ответы Дэвида-Асафа .

Другое решение — использовать RootModel :

      from pydantic import BaseModel, RootModel

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

class PersonList(RootModel):
    root: list[User]

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

это сработало для меня, используя понимание списка:

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

Я просто сидел в своем models.py список диктовок вроде этого:

      from django.db import models
from pydantic import BaseModel

class CustomList(BaseModel):
    data: list[dict]

У меня есть еще одна идея упростить этот код, если версия 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]
Другие вопросы по тегам