11 KiB
Тіло запиту - Вкладені моделі
З FastAPI Ви можете визначати, перевіряти, документувати та використовувати моделі, які можуть бути вкладені на будь-яку глибину (завдяки Pydantic).
Поля списку
Ви можете визначити атрибут як підтип. Наприклад, Python-список (list
):
{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
Це зробить tags
списком, хоча не визначається тип елементів списку.
Поля списку з параметром типу
Але Python має специфічний спосіб оголошення списків з внутрішніми типами або "параметрами типу":
Імпортуємо List
з модуля typing
У Python 3.9 і вище можна використовувати стандартний list
для оголошення таких типів, як ми побачимо нижче. 💡
Але в Python версії до 3.9 (від 3.6 і вище) спочатку потрібно імпортувати List
з модуля стандартної бібліотеки Python typing
:
{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
Оголошення list
з параметром типу
Щоб оголосити типи з параметрами типу (внутрішніми типами), такими як list
, dict
, tuple
:
- Якщо Ви використовуєте версію Python до 3.9, імпортуйте їх відповідну версію з модуля
typing
. - Передайте внутрішні типи як "параметри типу", використовуючи квадратні дужки:
[
and]
.
У Python 3.9 це буде виглядати так:
my_list: list[str]
У версіях Python до 3.9 це виглядає так:
from typing import List
my_list: List[str]
Це стандартний синтаксис Python для оголошення типів.
Використовуйте той самий стандартний синтаксис для атрибутів моделей з внутрішніми типами.
Отже, у нашому прикладі, ми можемо зробити tags
саме "списком рядків":
{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
Типи множин
Але потім ми подумали, що теги не повинні повторюватися, вони, ймовірно, повинні бути унікальними рядками.
І Python має спеціальний тип даних для множин унікальних елементів — це set
.
Тому ми можемо оголосити tags
як множину рядків:
{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
Навіть якщо Ви отримаєте запит з дубльованими даними, він буде перетворений у множину унікальних елементів.
І коли Ви будете виводити ці дані, навіть якщо джерело містить дублікати, вони будуть виведені як множина унікальних елементів.
І це буде анотовано/документовано відповідно.
Вкладені моделі
Кожен атрибут моделі Pydantic має тип.
Але цей тип сам може бути іншою моделлю Pydantic.
Отже, Ви можете оголосити глибоко вкладені JSON "об'єкти" з конкретними іменами атрибутів, типами та перевірками.
Усе це, вкладене без обмежень.
Визначення підмоделі
Наприклад, ми можемо визначити модель Image
:
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
Використання підмоделі як типу
А потім ми можемо використовувати її як тип атрибута:
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
Це означатиме, що FastAPI очікуватиме тіло запиту такого вигляду:
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2,
"tags": ["rock", "metal", "bar"],
"image": {
"url": "http://example.com/baz.jpg",
"name": "The Foo live"
}
}
Завдяки такій декларації у FastAPI Ви отримуєте:
- Підтримку в редакторі (автозавершення тощо), навіть для вкладених моделей
- Конвертацію даних
- Валідацію даних
- Автоматичну документацію
Спеціальні типи та валідація
Окрім звичайних типів, таких як str
, int
, float
, та ін. Ви можете використовувати складніші типи, які наслідують str
.
Щоб побачити всі доступні варіанти, ознайомтеся з оглядом типів у Pydantic. Деякі приклади будуть у наступних розділах.
Наприклад, у моделі Image
є поле url
, тому ми можемо оголосити його як HttpUrl
від Pydantic замість str
:
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
Рядок буде перевірено як дійсну URL-адресу і задокументовано в JSON Schema / OpenAPI як URL.
Атрибути зі списками підмоделей
У Pydantic Ви можете використовувати моделі як підтипи для list
, set
тощо:
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
Це означає, що FastAPI буде очікувати (конвертувати, валідувати, документувати тощо) JSON тіло запиту у вигляді:
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2,
"tags": [
"rock",
"metal",
"bar"
],
"images": [
{
"url": "http://example.com/baz.jpg",
"name": "The Foo live"
},
{
"url": "http://example.com/dave.jpg",
"name": "The Baz"
}
]
}
/// info | Інформація
Зверніть увагу, що тепер ключ images
містить список об'єктів зображень.
///
Глибоко вкладені моделі
Ви можете визначати вкладені моделі довільної глибини:
{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
/// info | Інформація
Зверніть увагу, що в моделі Offer
є список Item
ів, які, своєю чергою, можуть мати необов'язковий список Image
ів.
///
Тіла запитів, що складаються зі списків
Якщо верхній рівень JSON тіла, яке Ви очікуєте, є JSON масивом
(у Python — list
), Ви можете оголосити тип у параметрі функції, як і в моделях Pydantic:
images: List[Image]
або в Python 3.9 і вище:
images: list[Image]
наприклад:
{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
Підтримка в редакторі всюди
Ви отримаєте підтримку в редакторі всюди.
Навіть для елементів у списках:

Ви не змогли б отримати таку підтримку в редакторі, якби працювали напряму зі dict
, а не з моделями Pydantic.
Але Вам не потрібно турбуватися про це: вхідні dict'и автоматично конвертуються, а вихідні дані автоматично перетворюються в JSON.
Тіла з довільними dict
Ви також можете оголосити тіло як dict
з ключами одного типу та значеннями іншого типу.
Це корисно, якщо Ви не знаєте наперед, які імена полів будуть дійсними (як у випадку з моделями Pydantic).
Це буде корисно, якщо Ви хочете приймати ключі, які заздалегідь невідомі.
Це також зручно, якщо Ви хочете мати ключі іншого типу (наприклад, int
).
Ось що ми розглянемо далі.
У цьому випадку Ви можете приймати будь-який dict
, якщо його ключі — це int
, а значення — float
:
{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
/// tip | Порада
Майте на увазі, що в JSON тілі ключі можуть бути лише рядками (str
).
Але Pydantic автоматично конвертує дані.
Це означає, що навіть якщо клієнти вашого API надсилатимуть ключі у вигляді рядків, якщо вони містять цілі числа, Pydantic конвертує їх і проведе валідацію.
Тобто dict
, який Ви отримаєте як weights
, матиме ключі типу int
та значення типу float
.
///
Підсумок
З FastAPI Ви маєте максимальну гнучкість завдяки моделям Pydantic, зберігаючи при цьому код простим, коротким та елегантним.
А також отримуєте всі переваги:
- Підтримка в редакторі (автодоповнення всюди!)
- Конвертація даних (парсинг/сериалізація)
- Валідація даних
- Документація схем
- Автоматичне створення документації