Сьогодні ми заглибимось у створення складних моделей з кількома рівнями вкладеності. Це дозволить тобі ефективно обробляти дані навіть у великих і комплексних структурах, таких як JSON, де вкладеність неминуча. Так, JSON-структури можуть бути настільки ж хитромудрі, як черговий спосіб програмиста уникнути коментарів у коді, але разом ми з цим справимось!
У реальних проєктах ти часто стикаєшся з ситуаціями, коли потрібно працювати не з одномірними даними (наприклад, просто ім'я користувача або вік), а з більш складними структурами. Уяви, що потрібно створити API для реєстрації компанії, її співробітників і їх контактної інформації. Ці дані мають вкладену структуру. Pydantic дозволяє описувати і валідовувати такі структури даних простими і читабельними моделями.
Ці навички знадобляться тобі:
- При розробці API для складних систем (наприклад, CRM, ERP);
- При інтеграції з зовнішніми сервісами, де використовуються складні JSON-відповіді;
- При проєктуванні моделі даних у мікросервісній архітектурі.
Створюємо складну модель
Давай почнемо з прикладу. Припустимо, ми створюємо API для системи керування проєктами. У нас є сутності: проєкт, завдання в проєкті і відповідальні за завдання користувачі.
Ось приклад структури даних, яку ми хочемо отримати:
{
"id": 1,
"name": "FastAPI Development",
"tasks": [
{
"id": 101,
"title": "Set up project",
"completed": false,
"assigned_to": {
"id": 501,
"name": "Alice",
"email": "alice@example.com"
}
},
{
"id": 102,
"title": "Add authentication",
"completed": true,
"assigned_to": {
"id": 502,
"name": "Bob",
"email": "bob@example.com"
}
}
]
}
Приступимо до реалізації моделі.
Базові моделі
Спочатку створимо модель для користувача, бо вона використовується в задачі.
from pydantic import BaseModel, EmailStr
class User(BaseModel):
id: int
name: str
email: EmailStr
Тут усе просто: id — це ідентифікатор користувача, name — його ім'я, а email — електронна пошта (ми використовуємо тип EmailStr, щоб автоматично валідовувати формат email).
Тепер створимо модель для задачі.
from typing import Optional
from pydantic import BaseModel
class Task(BaseModel):
id: int
title: str
completed: bool
assigned_to: User | None # Поле може бути None
Модель Task містить:
id— ідентифікатор задачі;title— назва задачі;completed— булеве значення, що відображає статус задачі;assigned_to— інформація про користувача, якому призначена задача. Зверни увагу, що це поле має типUser! Це і є вкладеність. Поле вказано якOptional, тобто задача може бути без призначеного користувача.
Модель проєкту
Тепер створимо модель для проєкту, яка включає список задач.
from typing import List
class Project(BaseModel):
id: int
name: str
tasks: List[Task] # Список завдань
Модель Project містить:
id— ідентифікатор проєкту;name— назва проєкту;tasks— список об'єктівTask. ВикористовуємоList[Task]з модуляtyping.
Приклад складної моделі
З'єднаємо все разом та протестуємо.
from fastapi import FastAPI
app = FastAPI()
@app.post("/projects/")
def create_project(project: Project):
return {"message": "Project successfully created!", "data": project}
Запусти застосунок за допомогою uvicorn. Ось приклад запиту, який ми можемо відправити:
{
"id": 1,
"name": "FastAPI Development",
"tasks": [
{
"id": 101,
"title": "Set up project",
"completed": false,
"assigned_to": {
"id": 501,
"name": "Alice",
"email": "alice@example.com"
}
},
{
"id": 102,
"title": "Add authentication",
"completed": true,
"assigned_to": {
"id": 502,
"name": "Bob",
"email": "bob@example.com"
}
}
]
}
І ти отримаєш наступну відповідь:
{
"message": "Project successfully created!",
"data": {
"id": 1,
"name": "FastAPI Development",
"tasks": [
{
"id": 101,
"title": "Set up project",
"completed": false,
"assigned_to": {
"id": 501,
"name": "Alice",
"email": "alice@example.com"
}
},
{
"id": 102,
"title": "Add authentication",
"completed": true,
"assigned_to": {
"id": 502,
"name": "Bob",
"email": "bob@example.com"
}
}
]
}
}
Робота з валідацією у складних структурах
Pydantic автоматично перевіряє кожне поле на відповідність вказаному типу. Якщо якесь поле не відповідає, буде викинута помилка валідації.
Наприклад, надішлемо запит з некоректним email у користувача:
{
"id": 1,
"name": "FastAPI Development",
"tasks": [
{
"id": 101,
"title": "Set up project",
"completed": false,
"assigned_to": {
"id": 501,
"name": "Alice",
"email": "alice_at_example.com"
}
}
]
}
Відповідь:
{
"detail": [
{
"loc": ["body", "tasks", 0, "assigned_to", "email"],
"msg": "value is not a valid email address",
"type": "value_error.email"
}
]
}
Це повідомлення про помилку показує шлях, де саме виникла помилка: у першому елементі списку tasks в полі email.
Корисні поради
- Складні структури краще розбивати на окремі моделі. Не намагайся "запхати все в одну модель". Це ускладнює її підтримку.
- Використовуй описові назви. Назви моделей і полів мають бути зрозумілими.
- Тестуй вкладені структури. Іноді помилка на одному з рівнів може бути неочевидною.
Застосування у реальних проєктах
Складні вкладені моделі знаходять застосування у будь-якій системі, що працює з ієрархічними даними. Наприклад:
- Системи керування задачами (Trello, Jira);
- E-commerce платформи (товари, категорії, магазини);
- Інтеграція з зовнішніми API, особливо коли дані містять вкладені JSON-об'єкти.
Тепер ти знаєш, як проєктувати і валідовувати складні моделі за допомогою Pydantic. Готовий до задач реального світу? Погнали до наступних лекцій!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ