JavaRush /Курсы /Модуль 4: FastAPI /Изменение структуры базы данных с помощью миграций

Изменение структуры базы данных с помощью миграций

Модуль 4: FastAPI
7 уровень , 3 лекция
Открыта

Если вы не были с нами на предыдущих занятиях, то вероятно, находитесь в счастливом неведении о том, что модели данных и сама база данных не всегда синхронизированы "автоматически". А те, кто уже был здесь, точно знают: миграции — это ваш спасательный круг, который помогает удобно управлять изменениями и избегать хаоса в базе данных.

Начнём с того, как можно изменить структуру базы данных через модификацию ваших моделей данных. Задача предельно ясна: мы хотим, чтобы изменения в коде наших моделей синхронизировались с базой данных через Alembic.


Пример задачи

Предположим, у нас есть следующая модель данных:


# models.py
from sqlalchemy import Column, Integer, String
from database import Base

class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)

Мы поняли, что хотим добавить новое поле email, чтобы хранить почтовые адреса пользователей. Для этого просто изменим нашу модель:


class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    email = Column(String, unique=True, nullable=False)

Обратите внимание, что мы добавили новые ограничения:

  • unique=True: чтобы каждый email был уникальным.
  • nullable=False: поле обязательно для заполнения.

Теперь осталось синхронизировать эти изменения с базой данных через Alembic.


Генерация миграции для изменений

Чтобы Alembic "понял", что мы изменили в модели, и сгенерировал миграцию, используем команду:


alembic revision --autogenerate -m "Добавлено поле email в таблицу users"

Давайте разберём, что тут происходит:

  • revision: создаёт новую ревизию миграции.
  • --autogenerate: позволяет Alembic автоматически сгенерировать изменения на основе обновлённых моделей.
  • -m: добавляет комментарий или описание ревизии (очень полезно для истории миграций).

После выполнения команды Alembic сгенерирует новый файл миграции, который будет выглядеть примерно так:


"""Добавлено поле email в таблицу users"""

from alembic import op
import sqlalchemy as sa

# ID ревизии и родительской ревизии
revision = 'abcdef123456'
down_revision = '123456abcdef'
branch_labels = None
depends_on = None

def upgrade():
    # Добавление нового столбца
    op.add_column('users', sa.Column('email', sa.String(), nullable=False))
    op.create_unique_constraint('uq_users_email', 'users', ['email'])

def downgrade():
    # Удаление столбца (откат изменений)
    op.drop_constraint('uq_users_email', 'users', type_='unique')
    op.drop_column('users', 'email')

Применение миграции

Теперь, когда миграция готова, её нужно применить к базе данных. Для этого запускаем команду:


alembic upgrade head

Эта команда применяет все миграции, начиная с последней зафиксированной версии (если есть новые). После выполнения можно проверить структуру таблиц в базе данных, и вы увидите, что столбец email добавлен. Ура, успех!


Проверка изменений в базе данных

Чтобы убедиться, что всё работает правильно, можно воспользоваться любым инструментом для работы с базами данных. Например, в PostgreSQL можно выполнить:


\d users

И вы увидите, что столбец email добавлен. Кроме того, ограничения UNIQUE и NOT NULL также будут указаны.


Откат миграций

Случаются ситуации, когда нужно отменить изменения (например, у продакшена случился "нервный срыв"). Для этого нужно использовать команду:


alembic downgrade -1

Эта команда откатит последнюю выполненную миграцию. Если вы хотите вернуться к конкретной версии, можно указать её ID ревизии:


alembic downgrade 123456abcdef

После отката изменений столбец email будет удалён, и база данных вернётся к предыдущему состоянию.


Типичные ошибки и подводные камни

  1. Ошибка: "Target database is not up to date".
    Это может случиться, если вы забыли применить миграции до внесения новых изменений. Попробуйте выполнить alembic upgrade head перед созданием новой миграции.
  2. Конфликты между миграциями.
    Если несколько разработчиков параллельно работают над миграциями, легко столкнуться с конфликтами. Чтобы избежать этого, синхронизируйте свои изменения через Git и проводите обсуждения в команде.
  3. Ручная редакция миграций.
    Иногда Alembic может не распознать сложные изменения автоматически (например, изменение типа столбца). В таком случае придётся вручную редактировать файл миграции. Это нормально — просто будьте внимательны.

Пример использования в реальном проекте

Представьте, что вы работаете над крупным проектом e-commerce. Здесь базы данных меняются постоянно: добавляются новые модели, модифицируются существующие. Миграции помогают вам поддерживать синхронность между моделями и базой данных, даже если над проектом работает несколько команд.

Кроме того, откат миграций спасёт вас в случае необходимости быстрого восстановления, если что-то пойдёт не так. Например, вы добавили колонку и быстро поняли, что она не нужна (или хуже: сломала продакшен). С Alembic откат изменений — это несколько секунд, а не часы работы.


Теперь вы уверенно можете изменять структуру базы данных через Alembic, и это станет вашим незаменимым инструментом в дальнейшей работе. На следующих лекциях мы углубимся в управление версиями и интеграцию Alembic в более сложные проекты.

1
Задача
Модуль 4: FastAPI, 7 уровень, 3 лекция
Недоступна
Добавление нового столбца в таблицу
Добавление нового столбца в таблицу
1
Задача
Модуль 4: FastAPI, 7 уровень, 3 лекция
Недоступна
Изменение существующего столбца
Изменение существующего столбца
Комментарии (3)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
_den Уровень 77
21 марта 2026
решение первой задачи: - сразу удалить alembic - сделать alembic init (не забыть настроить url и metadata) - сделать миграцию для текущей базы - применить миграцию - добавить требуемую колонку - создать миграцию и применить - удалить файл первой миграции - 🤡
Александр Уровень 93
6 марта 2026
Исправьте вторую задачу. Токсичный бред! Решено с добавлением pydantic EmailStr и результатами pytest ( async )
Александр Уровень 93
6 марта 2026
Задача: Добавление нового столбца в таблицу Для начала, в alembic.ini нужно добавить секции handler_console formatter_generic Добавить prepend_sys_path = . Без них alembic не работает. Затем миграция...

# Добавляем новый столбец `price` с типом Float и ограничением NOT NULL
def upgrade():
# Тут сама задача


# Удаляем столбец `price` в случае отката миграции
def downgrade():
    op.drop_column("products", "price")

По условию задачи, price not null, и если товары уже есть в БД, то миграция не выполнится. результат у существующих позиций price=0 Останется изменить "Идентификаторы ревизии", чтобы миграция выполнялась после init миграции.😄