Тіло - Вкладені моделі¶
🌐 Переклад ШІ та людьми
Цей переклад виконано ШІ під керівництвом людей. 🤝
Можливі помилки через неправильне розуміння початкового змісту або неприродні формулювання тощо. 🤖
Ви можете покращити цей переклад, допомігши нам краще спрямовувати AI LLM.
З FastAPI ви можете визначати, перевіряти, документувати та використовувати моделі, які можуть бути вкладені на будь-яку глибину (завдяки Pydantic).
Поля списку¶
Ви можете визначити атрибут як підтип. Наприклад, Python-список (list):
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list = []
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Це зробить tags списком, хоча не визначається тип елементів списку.
Поля списку з параметром типу¶
Але Python має специфічний спосіб оголошення списків з внутрішніми типами або «параметрами типу»:
Оголошення list з параметром типу¶
Щоб оголосити типи з параметрами типу (внутрішніми типами), такими як list, dict, tuple,
передайте внутрішні тип(и) як «параметри типу», використовуючи квадратні дужки: [ та ]
my_list: list[str]
Це стандартний синтаксис Python для оголошення типів.
Використовуйте той самий стандартний синтаксис для атрибутів моделей з внутрішніми типами.
Отже, у нашому прикладі, ми можемо зробити tags саме «списком строк»:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list[str] = []
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Типи множин¶
Але потім ми подумали, що теги не повинні повторюватися, вони, ймовірно, повинні бути унікальними строками.
І Python має спеціальний тип даних для множин унікальних елементів - це set.
Тому ми можемо оголосити tags як множину строк:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Навіть якщо ви отримаєте запит з дубльованими даними, він буде перетворений у множину унікальних елементів.
І коли ви будете виводити ці дані, навіть якщо джерело містить дублікати, вони будуть виведені як множина унікальних елементів.
І це буде анотовано / документовано відповідно.
Вкладені моделі¶
Кожен атрибут моделі Pydantic має тип.
Але цей тип сам може бути іншою моделлю Pydantic.
Отже, ви можете оголосити глибоко вкладені JSON «об'єкти» з конкретними іменами атрибутів, типами та перевірками.
Усе це, вкладене без обмежень.
Визначення підмоделі¶
Наприклад, ми можемо визначити модель Image:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
image: Image | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Використання підмоделі як типу¶
А потім ми можемо використовувати її як тип атрибута:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
image: Image | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Це означатиме, що 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:
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
image: Image | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Строку буде перевірено як дійсну URL-адресу і задокументовано в Схемі JSON / OpenAPI як таку.
Атрибути зі списками підмоделей¶
У Pydantic ви також можете використовувати моделі як підтипи для list, set тощо:
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
images: list[Image] | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Це очікуватиме (конвертуватиме, валідуватиме, документуватиме тощо) тіло 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"
}
]
}
Примітка
Зверніть увагу, що тепер ключ images містить список об'єктів зображень.
Глибоко вкладені моделі¶
Ви можете визначати вкладені моделі довільної глибини:
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
images: list[Image] | None = None
class Offer(BaseModel):
name: str
description: str | None = None
price: float
items: list[Item]
@app.post("/offers/")
async def create_offer(offer: Offer):
return offer
Примітка
Зверніть увагу, що Offer має список Itemів, які, своєю чергою, мають необов'язковий список Imageів
Тіла запитів, що складаються зі списків¶
Якщо значення верхнього рівня JSON тіла, яке ви очікуєте, є JSON array (Python list), ви можете оголосити тип у параметрі функції так само, як у моделях Pydantic:
images: list[Image]
як у:
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
@app.post("/images/multiple/")
async def create_multiple_images(images: list[Image]):
return images
Підтримка в редакторі всюди¶
І ви отримаєте підтримку в редакторі всюди.
Навіть для елементів у списках:

Ви не змогли б отримати таку підтримку в редакторі, якби працювали напряму зі dict, а не з моделями Pydantic.
Але вам також не потрібно турбуватися про них: вхідні словники автоматично конвертуються, а вихідні дані автоматично перетворюються в JSON.
Тіла з довільними dict¶
Ви також можете оголосити тіло як dict з ключами одного типу та значеннями іншого типу.
Таким чином, вам не потрібно наперед знати, які імена полів/атрибутів є дійсними (як це було б у випадку з моделями Pydantic).
Це буде корисно, якщо ви хочете приймати ключі, які заздалегідь невідомі.
Інший корисний випадок - коли ви хочете мати ключі іншого типу (наприклад, int).
Ось що ми розглянемо тут.
У цьому випадку ви можете приймати будь-який dict, якщо він має ключі int зі значеннями float:
from fastapi import FastAPI
app = FastAPI()
@app.post("/index-weights/")
async def create_index_weights(weights: dict[int, float]):
return weights
Порада
Майте на увазі, що JSON підтримує лише str як ключі.
Але Pydantic має автоматичну конвертацію даних.
Це означає, що навіть якщо клієнти вашого API можуть надсилати лише строки як ключі, якщо ці строки містять цілі числа, Pydantic конвертує їх і проведе валідацію.
І dict, який ви отримаєте як weights, фактично матиме ключі типу int та значення типу float.
Підсумок¶
З FastAPI ви маєте максимальну гнучкість завдяки моделям Pydantic, зберігаючи при цьому код простим, коротким та елегантним.
Але з усіма перевагами:
- Підтримка в редакторі (автозавершення всюди!)
- Конвертація даних (також відома як парсинг / серіалізація)
- Валідація даних
- Документація схем
- Автоматична документація