Files
fastapi/docs/ru/docs/tutorial/body-nested-models.md
2024-11-18 03:25:44 +01:00

248 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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, сохраняя при этом простоту, краткость и элегантность вашего кода.
И дополнительно вы получаете:
* Поддержку редактора (автодополнение доступно везде!)
* Преобразование данных (также известно как парсинг / сериализация)
* Валидацию данных
* Документацию схемы данных
* Автоматическую генерацию документации