Тепер настав час закріпити вивчене на практиці, використовуючи PostgreSQL, і зрозуміти, як Alembic допомагає спрощувати роботу зі змінами в реальному проєкті.
Основна мета цієї частини лекції — застосувати міграції Alembic на практиці: налаштувати PostgreSQL, внести зміни в існуючу структуру бази даних і виконати міграції.
Встановлення PostgreSQL і підключення до проєкту FastAPI
Якщо в тебе ще не налаштований PostgreSQL, час це виправити. Для локальної роботи ти можеш використовувати Docker (твій найкращий друг, коли йдеться про бази даних):
docker run --name postgres_alembic_example -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=admin -e POSTGRES_DB=example_db -p 5432:5432 -d postgres
Цей контейнер створить PostgreSQL-сервер з користувачем admin, паролем admin і базою даних example_db на порту 5432.
Тепер оновимо підключення до бази даних у твоєму проєкті FastAPI. У файлі settings.py (або його аналогу) вкажи:
DATABASE_URL = "postgresql+psycopg2://admin:admin@localhost:5432/example_db"
І не забудь переконатися, що в тебе встановлений пакет psycopg2 для роботи з PostgreSQL:
pip install psycopg2
Налаштування Alembic для роботи з PostgreSQL
Якщо Alembic вже був ініціалізований у твоєму проєкті, просто переконайся, що в файлі alembic.ini вказано правильний рядок підключення до бази даних:
sqlalchemy.url = postgresql+psycopg2://admin:admin@localhost:5432/example_db
Якщо ж Alembic ще не ініціалізований, виконай команду:
alembic init alembic
Переконайся, що файл env.py налаштований для взаємодії з твоїми моделями і базою даних. Наприклад:
from myapp.models import Base # Імпортуй свій базовий клас із models
def run_migrations_online():
...
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=Base.metadata # Вказуємо твої моделі для аналізу
)
...
Якщо ти пропустив налаштування env.py у попередніх лекціях, повернись до них, щоб відновити послідовність.
Зміна структури таблиці за допомогою Alembic
Припустимо, у тебе вже є таблиця users у базі даних. Вона може виглядати так:
# models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
email = Column(String, unique=True, index=True, nullable=False)
А тепер потрібно додати нове поле age і змінити тип даних email, щоб він став необов'язковим.
Генерація міграції
Спочатку змінюємо нашу модель:
# models.py
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
email = Column(String, unique=True, index=True) # Прибрано nullable=False
age = Column(Integer, nullable=True) # Нове поле для віку
Тепер запускаємо автогенерацію міграції:
alembic revision --autogenerate -m "Add age and make email nullable"
Alembic створить файл міграції в папці alembic/versions/. Його структура приблизно така:
def upgrade():
# команда для додавання колонок
op.add_column("users", sa.Column("age", sa.Integer(), nullable=True))
# команда для зміни існуючих колонок
op.alter_column("users", "email", existing_type=sa.String(), nullable=True)
def downgrade():
# команда для відкату доданої колонки
op.drop_column("users", "age")
# команда для повернення зміни типу даних
op.alter_column("users", "email", existing_type=sa.String(), nullable=False)
Застосовуємо зміни до бази даних:
alembic upgrade head
Тепер структура таблиці оновлена! Ти можеш перевірити зміни безпосередньо в PostgreSQL:
\d users
Управління версіонністю і відкат змін
Alembic дозволяє легко керувати версіями міграцій, зберігати історію змін і відкатувати помилки.
Щоб перевірити поточну версію бази даних, виконай команду:
alembic current
У відповідь ти побачиш ідентифікатор міграції:
Current revision for default: <revision_id>
Якщо ти раптом зрозумів, що додавання поля age було помилкою (наприклад, через накладні витрати), відкатай міграцію:
alembic downgrade -1
Після цього Alembic поверне базу даних до попередньої версії. Для перевірки знову виконай:
alembic current
Ти також можеш відкотитися не лише на одну ревізію, а до конкретної версії, вказавши її ідентифікатор:
alembic downgrade <revision_id>
Приклад повного сценарію міграцій
Давай розглянемо послідовність задач, які можуть виникнути в реальному проєкті.
Сценарій: додаємо адресу користувача.
Потрібно додати таблицю addresses, пов'язану з таблицею users. Це виглядає так:
# models.py
class Address(Base):
__tablename__ = "addresses"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"))
address_line = Column(String, nullable=False)
city = Column(String, nullable=False)
country = Column(String, nullable=False)
Створюємо міграцію для нової таблиці:
alembic revision --autogenerate -m "Create addresses table"
Файл міграції може виглядати так:
def upgrade():
op.create_table(
"addresses",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("user_id", sa.Integer(), nullable=True),
sa.Column("address_line", sa.String(), nullable=False),
sa.Column("city", sa.String(), nullable=False),
sa.Column("country", sa.String(), nullable=False),
sa.ForeignKeyConstraint(["user_id"], ["users.id"]),
sa.PrimaryKeyConstraint("id"),
)
def downgrade():
op.drop_table("addresses")
Застосовуємо міграцію:
alembic upgrade head
Тепер у тебе є таблиця addresses, пов'язана з таблицею users!
Поширені помилки та їх вирішення
- "Target database is not up to date". Це трапляється, якщо ти забув застосувати міграції перед зміною структури бази даних вручну. Переконайся, що база даних і міграції синхронізовані.
- Помилка підключення до бази даних. Перевір, чи правильно вказані параметри в
alembic.ini. - Конфлікти ревізій у команді. Використай
alembic merge, якщо два розробники випадково створили міграції з одного стану бази даних і вони конфліктують.
Управління міграціями і версіями в PostgreSQL через Alembic — це процес, який може стати основою стабільності твоєї бази даних. Тепер ти готовий до складніших задач і впевненіше почуваєшся при внесенні змін у проєкти!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ