# Тіло - Вкладені моделі { #body-nested-models }

З **FastAPI** ви можете визначати, перевіряти, документувати та використовувати моделі, які можуть бути вкладені на будь-яку глибину (завдяки Pydantic).

## Поля списку { #list-fields }

Ви можете визначити атрибут як підтип. Наприклад, Python-список (`list`):

{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}

Це зробить `tags` списком, хоча не визначається тип елементів списку.

## Поля списку з параметром типу { #list-fields-with-type-parameter }

Але Python має специфічний спосіб оголошення списків з внутрішніми типами або «параметрами типу»:

### Оголошення `list` з параметром типу { #declare-a-list-with-a-type-parameter }

Щоб оголосити типи з параметрами типу (внутрішніми типами), такими як `list`, `dict`, `tuple`,
передайте внутрішні тип(и) як «параметри типу», використовуючи квадратні дужки: `[` and `]`

```Python
my_list: list[str]
```

Це стандартний синтаксис Python для оголошення типів.

Використовуйте той самий стандартний синтаксис для атрибутів моделей з внутрішніми типами.

Отже, у нашому прикладі, ми можемо зробити `tags` саме «списком рядків»:

{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}

## Типи множин { #set-types }

Але потім ми подумали, що теги не повинні повторюватися, вони, ймовірно, повинні бути унікальними рядками.

І Python має спеціальний тип даних для множин унікальних елементів — це `set`.

Тому ми можемо оголосити `tags` як множину рядків:

{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}

Навіть якщо ви отримаєте запит з дубльованими даними, він буде перетворений у множину унікальних елементів.

І коли ви будете виводити ці дані, навіть якщо джерело містить дублікати, вони будуть виведені як множина унікальних елементів.

І це буде анотовано/документовано відповідно.

## Вкладені моделі { #nested-models }

Кожен атрибут моделі Pydantic має тип.

Але цей тип сам може бути іншою моделлю Pydantic.

Отже, ви можете оголосити глибоко вкладені JSON «об'єкти» з конкретними іменами атрибутів, типами та перевірками.

Усе це, вкладене без обмежень.

### Визначення підмоделі { #define-a-submodel }

Наприклад, ми можемо визначити модель `Image`:

{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}

### Використання підмоделі як типу { #use-the-submodel-as-a-type }

А потім ми можемо використовувати її як тип атрибута:

{* ../../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** ви отримуєте:

* Підтримку в редакторі (автозавершення тощо), навіть для вкладених моделей
* Конвертацію даних
* Валідацію даних
* Автоматичну документацію

## Спеціальні типи та валідація { #special-types-and-validation }

Окрім звичайних типів, таких як `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 Schema / OpenAPI як URL.

## Атрибути зі списками підмоделей { #attributes-with-lists-of-submodels }

У Pydantic ви можете використовувати моделі як підтипи для `list`, `set` тощо:

{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}

Це означає, що **FastAPI** буде очікувати (конвертувати, валідувати, документувати тощо) 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` містить список об'єктів зображень.

///

## Глибоко вкладені моделі { #deeply-nested-models }

Ви можете визначати вкладені моделі довільної глибини:

{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}

/// info | Інформація

Зверніть увагу, що в моделі `Offer` є список `Item`ів, які, своєю чергою, можуть мати необов'язковий список `Image`ів.

///

## Тіла запитів, що складаються зі списків { #bodies-of-pure-lists }

Якщо верхній рівень JSON тіла, яке ви очікуєте, є JSON `масивом` (у Python — `list`), ви можете оголосити тип у параметрі функції, як і в моделях Pydantic:

```Python
images: list[Image]
```

наприклад:

{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}

## Підтримка в редакторі всюди { #editor-support-everywhere }

Ви отримаєте підтримку в редакторі всюди.

Навіть для елементів у списках:

<img src="/img/tutorial/body-nested-models/image01.png">

Ви не змогли б отримати таку підтримку в редакторі, якби працювали напряму зі  `dict`, а не з моделями Pydantic.

Але вам не потрібно турбуватися про це: вхідні dict'и автоматично конвертуються, а вихідні дані автоматично перетворюються в JSON.

## Тіла з довільними `dict` { #bodies-of-arbitrary-dicts }

Ви також можете оголосити тіло як `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`.

///

## Підсумок { #recap }

З **FastAPI** ви маєте максимальну гнучкість завдяки моделям Pydantic, зберігаючи при цьому код простим, коротким та елегантним.

А також отримуєте всі переваги:

* Підтримка в редакторі (автодоповнення всюди!)
* Конвертація даних (парсинг/сериалізація)
* Валідацію даних
* Документація схем
* Автоматичне створення документації
