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

Пример работы с 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  # Импортирайте ваш базовый класс из моделей

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

1
Задача
Модуль 4: FastAPI, 7 уровень, 8 лекция
Недоступна
Инициализация Alembic для PostgreSQL
Инициализация Alembic для PostgreSQL
1
Задача
Модуль 4: FastAPI, 7 уровень, 8 лекция
Недоступна
Создание миграции для новой таблицы
Создание миграции для новой таблицы
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
_den Уровень 77
25 марта 2026
чтобы в первой задаче обойти валидатор на четвертом условии нужно заменить все содержимое env.py на print("base") 🤡