Ось готовий урок, створений за твоїм майстер-промптом.
🎓 УРОК: Валідація даних з Pydantic
Привіт, друзі! Радий бачити вас на цьому уроці. Сьогодні ми поговоримо про те, що відокремлює надійний, професійний код від "скрипта, який я написав за 5 хвилин і який падає щоразу, коли користувач натискає не ту кнопку".
Ми розберемо Pydantic.
1. 🔥 Вступ: Фейс-контроль для вашої програми
Уявіть, що ви власник елітного нічного клубу (це ваша програма). Всередині — вечірка: працює складна логіка, бази даних записують транзакції, процесори обробляють запити.
А тепер уявіть, що на вході немає охорону.
Що станеться? Хтось зайде з брудом на взутті (невірний формат даних). Хтось принесе зброю (SQL-ін'єкції або шкідливі скрипти). А хтось взагалі не людина, а ведмідь на велосипеді (об'єкт зовсім іншого типу).
Ваша вечірка закінчиться катастрофою. Програма впаде з помилкою TypeError або KeyError десь глибоко в надрах коду, і ви будете годинами шукати, де саме це сталося.
Риторичне питання: Ви б хотіли перевіряти паспорт і дрес-код на вході, чи розбиратися з проблемами вже на танцполі?
Звісно, на вході! Ось тут і вступає в гру Pydantic.
Це ваш ідеальний охоронець. Ви даєте йому інструкцію (схему), і він каже кожному шматочку даних: "Ти проходиш, ти — ні, а ти — вдягни краватку (конвертуйся в правильний тип), і тоді заходь".
2. 🧠 Теоретична база: Як це працює?
Pydantic — це бібліотека для Python, яка використовує Type Hints (підказки типів), щоб перевіряти дані.
Але тут є важливий нюанс. Запам’ятайте це:
💡 Pydantic — це не просто валідатор, це парсер.
Що це означає?
Якщо ваша функція очікує ціле число (int), а ви передаєте рядок "42", звичайний валідатор скаже: "Помилка! Це рядок!".
Pydantic скаже: "Хм, це схоже на число. Я перетворю це на int (42) і пропущу далі". Він намагається зрозуміти дані і привести їх до потрібного вигляду.
Як це виглядає "під капотом"?
- Ви створюєте клас, який успадковується від
BaseModel. - Описуєте поля, використовуючи стандартні типи Python (
str,int,list,bool). - Коли ви створюєте об'єкт цього класу, Pydantic біжить по всіх полях і перевіряє їх.
Якщо все ок — у вас є об'єкт з гарантовано правильними типами.
Якщо ні — Pydantic викидає детальну помилку (ValidationError), де чітко написано, що і де пішло не так.
3. 🧪 Приклади
Приклад 1: "Мінімальний"
Уявіть, що ми реєструємо користувача. Нам потрібні його id та name.
Питання до вас: Що буде, якщо ми передамо id як рядок "123"?
Дивимось код:
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
# Спроба 1: Ідеальні дані
user1 = User(id=1, name="David")
print(user1)
# id=1 name='David'
# Спроба 2: id як рядок "123"
user2 = User(id="123", name="Alice")
print(user2)
# id=123 name='Alice' <-- ДИВІТЬСЯ! Воно стало числом (int)!
Пояснення: Pydantic зробив приведення типів (coercion). Це неймовірно зручно при роботі з API, де всі дані часто приходять як рядки (наприклад, з URL-параметрів).
Приклад 2: "Реальний світ"
Давайте ускладнимо. У нас є інтернет-магазин. Товар має ціну, список тегів і статус наявності.
from typing import List, Optional
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
tags: List[str] = [] # Значення за замовчуванням - порожній список
is_active: bool = True
# Приходять "брудні" JSON-дані
raw_data = {
"name": "Super Laptop",
"price": "999.50", # Рядок!
"tags": ["tech", 123], # Один тег - число?!
"is_active": "yes" # Рядок замість булевого значення!
}
item = Item(**raw_data) # Розпаковка словника
print(item)
Питання: Чи впаде код?
* price: рядок "999.50" -> float 999.5. ✅
* tags: число 123 -> рядок "123". ✅
* is_active: "yes" -> Pydantic достатньо розумний, щоб зрозуміти, що "yes", "on", "1", "true" — це True. ✅
Результат:
name='Super Laptop' price=999.5 tags=['tech', '123'] is_active=True
Ми отримали чисті, типізовані дані, з якими безпечно працювати далі.
Приклад 3: "Коли все погано"
А тепер спробуємо зламати систему.
try:
User(id="abc", name="Hacker") # "abc" не можна перетворити на int
except Exception as e:
print(e)
Ви побачите ValidationError. Це не просто "Error". Там буде написано:
* loc=('id',) — помилка в полі id.
* msg='Input should be a valid integer...' — що саме не так.
Це дозволяє вам автоматично віддавати клієнту API красиву відповідь: "Друже, ти помилився в полі id, виправ, будь ласка".
4. 🛠 Практична частина
Час братися за клавіатуру! Виконайте ці завдання по черзі.
🔹 Завдання 1: Основи
Створіть модель Book (Книга) з полями:
* title (рядок)
* pages (ціле число)
* rating (дробове число, float)
Створіть об'єкт цієї книги, передавши правильні дані. Виведіть його model_dump() (це перетворить об'єкт назад у словник).
🔹 Завдання 2: "Зламай мене"
Спробуйте створити об'єкт Book, передавши в pages значення "багато". Огорніть це в блок try...except ValidationError і виведіть помилку в консоль. Прочитайте її.
🔹 Завдання 3: Вкладеність
Уявіть, що у Книги є Автор.
1. Створіть модель Author (name: str, age: int).
2. Додайте поле author типу Author у модель Book.
3. Спробуйте створити книгу з вкладеним словником автора.
Приклад даних: {"title": "Dune", "pages": 800, "rating": 4.9, "author": {"name": "Frank", "age": 65}}
🔹 Завдання 4: Міні-кейс (Валідатор)
Реальна задача: ціна не може бути від'ємною.
Використовуйте декоратор @field_validator.
(Підказка: погугліть pydantic field_validator або спробуйте інтуїтивно).
from pydantic import field_validator
class Product(BaseModel):
price: float
@field_validator('price')
@classmethod
def check_positive(cls, v: float):
if v < 0:
raise ValueError('Ціна має бути більше 0')
return v
Реалізуйте це і перевірте на Product(price=-5).
🔹 Питання "А що, якщо..."
Що, якщо в JSON прийде поле, якого немає в нашій моделі (зайве сміття)? Pydantic за замовчуванням його проігнорує. Але чи можна налаштувати так, щоб він забороняв зайві поля? (Ключове слово для пошуку: model_config = {'extra': 'forbid'}).
5. 💡 Мислення як у розробника
Як думає новачок?
"Я просто напишу if data['age'] > 0 в середині функції".
Це призводить до "спагеті-коду", де бізнес-логіка змішана з перевірками типів.
Як думає Senior Developer?
1. Fail Fast (Падай швидко): Якщо дані криві, я хочу знати про це на першій мілісекунді, а не після того, як почав запис у базу даних.
2. Single Source of Truth: Моя модель Pydantic — це документація. Якщо я дивлюсь на клас User, я точно знаю, як виглядає користувач. Мені не треба читати код функції.
3. Не довіряй нікому: Фронтенд може помилитися. Інший мікросервіс може надіслати нісенітницю. Pydantic — це мій бронежилет.
Типова помилка:
Забувати про Optional. Якщо поле може бути None, обов'язково пишіть Optional[str] (або str | None у Python 3.10+). Інакше, якщо прийде null, буде помилка.
6. 🧩 Підсумок
Отже, що ми сьогодні отримали?
- Ви зрозуміли, що валідація — це безпека і стабільність.
- Ви навчилися створювати Pydantic-моделі.
- Ви побачили, як Pydantic автоматично конвертує типи (магія!).
- Ви знаєте, як обробляти помилки.
Тепер ви вмієте будувати надійний "фільтр" на вході у ваші програми. Ваші функції більше не повинні перевіряти, чи є число числом. Вони просто роблять свою роботу.
🚀 Тизер наступного уроку: Тепер, коли ми вміємо описувати дані, як нам створити повноцінний веб-сервер, який приймає ці дані, обробляє їх і віддає відповідь? У наступному уроці ми познайомимось із найкращим другом Pydantic — фреймворком FastAPI. Готуйтесь, буде швидко!
А зараз — вперед до практики! Чекаю на ваші рішення! 👋