You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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, зберігаючи при цьому код простим, коротким та елегантним.

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

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