JavaRush /Курси /Модуль 4: FastAPI /Приклад роботи з Alembic і управління версіями в PostgreS...

Приклад роботи з Alembic і управління версіями в PostgreSQL

Модуль 4: FastAPI
Рівень 7 , Лекція 8
Відкрита

Тепер настав час закріпити вивчене на практиці, використовуючи 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 — це процес, який може стати основою стабільності твоєї бази даних. Тепер ти готовий до складніших задач і впевненіше почуваєшся при внесенні змін у проєкти!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ