Ось готовий урок, згенерований за твоїм майстер-промптом. Це класичний CS50-вайб: енергійно, зрозуміло і з фокусом на суті.
🎓 Тема: Міграції бази даних з Alembic
Привіт, світе! 👋 Радий бачити вас. Сьогодні ми торкнемося теми, яка відрізняє аматорський код від професійної інженерії. Ми говоритимемо про зміни.
1. 🔥 Вступ: Коли "DROP TABLE" — це не вихід
Уявіть ситуацію. Ви пишете стартап — нову соціальну мережу. У вас є база даних, є таблиця Users, і там є поля name та email. Ви запускаєте проєкт, перші 100 користувачів реєструються. Ура! 🎉
Але наступного ранку маркетинг каже: "Слухай, нам терміново треба додати поле age (вік), щоб показувати правильну рекламу".
Ви відкриваєте код, додаєте поле в модель... і тут виникає проблема. Ваш код (Python) тепер очікує поле age, а ваша реальна база даних (PostgreSQL/MySQL) про нього ні сном ні духом.
Що робити?
- Варіант "Студентський": Видалити таблицю (разом зі 100 користувачами) і створити нову.
- Результат: Маркетологи плачуть, інвестори йдуть, ви звільнені. ❌
- Варіант "Ковбойський": Зайти в консоль бази даних і писати вручну
ALTER TABLE users ADD COLUMN age...- Результат: Це працює на вашому ноутбуці. Але як це перенести на сервер? А якщо у вас 5 розробників? А якщо ви помилилися в синтаксисі на продакшені? Хаос. ❌
Хіба не було б чудово мати "машину часу" для бази даних? Інструмент, який дозволяє безпечно додавати кімнати до вашого будинку, не зносячи його до фундаменту?
Саме для цього існує Alembic.
2. 🧠 Теоретична база: Гіт для вашої бази
Що таке Alembic? Якщо Git — це система контролю версій для вашого коду, то Alembic — це система контролю версій для вашої схеми бази даних.
Як це працює "під капотом"?
Уявіть Alembic як архітектора-посередника. 1. З одного боку у нього є ваші Python-моделі (SQLAlchemy) — це те, як база має виглядати. 2. З іншого — реальна база даних — те, як вона виглядає зараз.
Alembic дивиться на обидва боки, знаходить різницю і генерує скрипт міграції.
Ключові поняття (запам’ятайте це!):
- Migration (Міграція / Ревізія): Це маленький файл на Python, інструкція. Він каже: "Додай колонку Х" або "Створи таблицю Y".
- Upgrade (Оновлення): Застосування змін (рух у майбутнє ➡).
- Downgrade (Відкат): Скасування змін (рух у минуле ⬅). Це ваша кнопка "Undo", якщо щось пішло не так.
- alembic_version: Спеціальна маленька табличка, яку Alembic створює у вашій базі. Там зберігається лише одне значення — ID поточної міграції. Так він знає, на якому етапі історії ми знаходимось.
Інтуїтивно: Міграція — це як чекпойнт у грі. Ви пройшли рівень (змінили структуру БД) — збереглися. Якщо бос вас вбив (код впав) — завантажили попередній чекпойнт.
3. 🧪 Приклади: Від магії до контролю
Давайте налаштуємо це. Я буду використовувати аналогію з будівництвом.
Крок 0: Ініціалізація (Закладаємо фундамент)
У терміналі вашого проєкту:
alembic init alembic
Ви побачите нову папку alembic/. Найважливіший файл там — env.py.
Завдання розробника: У цьому файлі треба підказати Alembic, де лежать ваші моделі (метадані).
# У файлі alembic/env.py
from my_app.models import Base # Імпортуємо ваші моделі
target_metadata = Base.metadata # Кажемо Alembic: "Дивись сюди!"
Приклад 1: Перша міграція (Створюємо світ)
У нас є модель:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
Ми кажемо Alembic: "Зроби зліпок стану бази".
alembic revision --autogenerate -m "Initial migration"
Alembic створить файл у папці versions/. Давайте заглянемо всередину. Що ви очікуєте там побачити? SQL? Ні, там Python!
def upgrade():
# Alembic каже: Створи таблицю users
op.create_table('users',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
def downgrade():
# Якщо треба відкотитися - видали таблицю
op.drop_table('users')
Застосовуємо (будуємо дім):
alembic upgrade head
head означає "остання, найновіша версія".
Приклад 2: Зміни в реальному часі (Додаємо вік)
Тепер змінимо модель у коді:
class User(Base):
# ... старі поля ...
age = Column(Integer, default=18) # <-- Нове поле!
Робимо нову міграцію:
alembic revision --autogenerate -m "Add age column"
alembic upgrade head
Вуаля! Ваша база оновилася, дані користувачів збереглися, а нова колонка з’явилася.
4. 🛠 Практична частина
Тепер ваша черга. Не бійтеся помилятися — це локальна база даних.
- 🔹 База: Ініціалізуйте Alembic у новому проєкті. Створіть просту модель
Product(назва, ціна). Згенеруйте та застосуйте першу міграцію. - 🔹 Зміна: Додайте до товару поле
in_stock(булеве значення). Згенеруйте міграцію. Застосуйте її. Перевірте через DBeaver або pgAdmin, чи з'явилася колонка. - 🔹 Відкат: Упс,
in_stockне потрібен! Виконайте командуalembic downgrade -1. Переконайтеся, що колонка зникла, але таблиця лишилася. - 🔹 Виклик: Спробуйте перейменувати поле в моделі (наприклад,
price->amount). Зробіть--autogenerate.- Питання: Чи зрозумів Alembic, що це перейменування, чи він видалив стару колонку і створив нову? (Спойлер: часто він думає, що це видалення+створення, що призведе до втрати даних. Подивіться, як виправити це в згенерованому файлі вручну за допомогою
op.alter_column).
- Питання: Чи зрозумів Alembic, що це перейменування, чи він видалив стару колонку і створив нову? (Спойлер: часто він думає, що це видалення+створення, що призведе до втрати даних. Подивіться, як виправити це в згенерованому файлі вручну за допомогою
- 🔹 Кейс "А що, якщо": Що буде, якщо ви додасте колонку
NOT NULL(обов'язкову) в таблицю, де вже є записи? Як база даних заповнить це поле для існуючих записів?- Підказка: Вам доведеться встановити дефолтне значення або наповнити дані перед встановленням обмеження
NOT NULL.
- Підказка: Вам доведеться встановити дефолтне значення або наповнити дані перед встановленням обмеження
5. 💡 Мислення як у розробника
Ось декілька секретів, які відрізняють "сеньйорів" від новачків:
-
Ніколи не довіряйте
--autogenerateсліпо. Alembic розумний, але не геній. Він може не помітити зміну назви таблиці або складні зміни типів даних. Правило: Завжди відкривайте згенерований файл міграції та читайте його очима перед тим, як робитиupgrade. -
Міграції — це частина коду. Файли міграцій комітяться в Git. Якщо ваш колега підтягує ваш код, він повинен мати змогу запустити
alembic upgrade headі отримати ідентичну базу даних. -
Не змінюйте старі міграції. Якщо ви вже застосували міграцію і закомітили її, ніколи не редагуйте цей файл. Створіть нову міграцію, яка виправляє помилки попередньої. Історія має бути лінійною і недоторканною.
6. 🧩 Підсумок
Отже, що ми маємо? * Ми більше не видаляємо бази даних, щоб додати колонку. * Ми маємо повну історію змін нашої структури (хто, коли і що додав). * Ми можемо подорожувати в часі (upgrade/downgrade).
Ви тепер володієте інструментом, який дозволяє вашому проєкту рости від "гаражного прототипу" до "корпоративного монстра" без втрати даних.
🔍 Що далі? Тепер, коли у нас є ідеальна структура бази даних, настав час наповнити її даними та навчитися діставати їх максимально ефективно. Наступного разу ми поговоримо про складні запити, JOIN-и та проблему N+1. Це буде цікаво!
А поки що — alembic upgrade head і до зустрічі! 💻🚀