mirror of
https://github.com/fastapi/fastapi.git
synced 2026-03-13 12:27:46 -04:00
248 lines
12 KiB
Markdown
248 lines
12 KiB
Markdown
# Body - Вложенные модели
|
||
|
||
С помощью **FastAPI**, вы можете определять, валидировать, документировать и использовать модели произвольной вложенности (благодаря библиотеке Pydantic).
|
||
|
||
## Определение полей содержащих списки
|
||
|
||
Вы можете определять атрибут как подтип. Например, тип `list` в Python:
|
||
|
||
{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
|
||
|
||
Это приведёт к тому, что обьект `tags` преобразуется в список, несмотря на то что тип его элементов не объявлен.
|
||
|
||
## Определение полей содержащих список с определением типов его элементов
|
||
|
||
Однако в Python есть способ объявления списков с указанием типов для вложенных элементов:
|
||
|
||
### Импортируйте `List` из модуля typing
|
||
|
||
В Python 3.9 и выше вы можете использовать стандартный тип `list` для объявления аннотаций типов, как мы увидим ниже. 💡
|
||
|
||
Но в версиях Python до 3.9 (начиная с 3.6) сначала вам необходимо импортировать `List` из стандартного модуля `typing` в Python:
|
||
|
||
{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
|
||
|
||
### Объявление `list` с указанием типов для вложенных элементов
|
||
|
||
Объявление типов для элементов (внутренних типов) вложенных в такие типы как `list`, `dict`, `tuple`:
|
||
|
||
* Если у вас Python версии ниже чем 3.9, импортируйте их аналог из модуля `typing`
|
||
* Передайте внутренний(ие) тип(ы) как "параметры типа", используя квадратные скобки: `[` и `]`
|
||
|
||
В Python версии 3.9 это будет выглядеть так:
|
||
|
||
```Python
|
||
my_list: list[str]
|
||
```
|
||
|
||
В версиях Python до 3.9 это будет выглядеть так:
|
||
|
||
```Python
|
||
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** будет ожидать тело запроса, аналогичное этому:
|
||
|
||
```JSON
|
||
{
|
||
"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** вы получите:
|
||
|
||
* Поддержку редакторов IDE (автодополнение и т.д), даже для вложенных моделей
|
||
* Преобразование данных
|
||
* Валидацию данных
|
||
* Автоматическую документацию
|
||
|
||
## Особые типы и валидация
|
||
|
||
Помимо обычных простых типов, таких как `str`, `int`, `float`, и т.д. Вы можете использовать более сложные базовые типы, которые наследуются от типа `str`.
|
||
|
||
Чтобы увидеть все варианты, которые у вас есть, ознакомьтесь с документацией <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">по необычным типам Pydantic</a>. Вы увидите некоторые примеры в следующей главе.
|
||
|
||
Например, так как в модели `Image` у нас есть поле `url`, то мы можем объявить его как тип `HttpUrl` из модуля Pydantic вместо типа `str`:
|
||
|
||
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
|
||
|
||
Строка будет проверена на соответствие допустимому URL-адресу и задокументирована в JSON схему / OpenAPI.
|
||
|
||
## Атрибуты, содержащие списки подмоделей
|
||
|
||
Вы также можете использовать модели Pydantic в качестве типов вложенных в `list`, `set` и т.д:
|
||
|
||
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
|
||
|
||
Такая реализация будет ожидать (конвертировать, валидировать, документировать и т.д) JSON-содержимое в следующем формате:
|
||
|
||
```JSON hl_lines="11"
|
||
{
|
||
"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 `array` (в Python - `list`), вы можете объявить тип в параметре функции, так же, как в моделях Pydantic:
|
||
|
||
```Python
|
||
images: List[Image]
|
||
```
|
||
|
||
в Python 3.9 и выше:
|
||
|
||
```Python
|
||
images: list[Image]
|
||
```
|
||
|
||
например так:
|
||
|
||
{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
|
||
|
||
## Универсальная поддержка редактора
|
||
|
||
И вы получаете поддержку редактора везде.
|
||
|
||
Даже для элементов внутри списков:
|
||
|
||
<img src="/img/tutorial/body-nested-models/image01.png">
|
||
|
||
Вы не могли бы получить такую поддержку редактора, если бы работали напрямую с `dict`, а не с моделями Pydantic.
|
||
|
||
Но вы также не должны беспокоиться об этом, входящие словари автоматически конвертируются, а ваш вывод также автоматически преобразуется в формат 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`, который вы получите в качестве ответа Pydantic, действительно будет иметь ключи типа `int` и значения типа `float`.
|
||
|
||
///
|
||
|
||
## Резюме
|
||
|
||
С помощью **FastAPI** вы получаете максимальную гибкость, предоставляемую моделями Pydantic, сохраняя при этом простоту, краткость и элегантность вашего кода.
|
||
|
||
И дополнительно вы получаете:
|
||
|
||
* Поддержку редактора (автодополнение доступно везде!)
|
||
* Преобразование данных (также известно как парсинг / сериализация)
|
||
* Валидацию данных
|
||
* Документацию схемы данных
|
||
* Автоматическую генерацию документации
|