Если вы не были с нами на предыдущих занятиях, то вероятно, находитесь в счастливом неведении о том, что модели данных и сама база данных не всегда синхронизированы "автоматически". А те, кто уже был здесь, точно знают: миграции — это ваш спасательный круг, который помогает удобно управлять изменениями и избегать хаоса в базе данных.
Начнём с того, как можно изменить структуру базы данных через модификацию ваших моделей данных. Задача предельно ясна: мы хотим, чтобы изменения в коде наших моделей синхронизировались с базой данных через 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 будет удалён, и база данных вернётся к предыдущему состоянию.
Типичные ошибки и подводные камни
- Ошибка: "Target database is not up to date".
Это может случиться, если вы забыли применить миграции до внесения новых изменений. Попробуйте выполнитьalembic upgrade headперед созданием новой миграции. - Конфликты между миграциями.
Если несколько разработчиков параллельно работают над миграциями, легко столкнуться с конфликтами. Чтобы избежать этого, синхронизируйте свои изменения через Git и проводите обсуждения в команде. - Ручная редакция миграций.
Иногда Alembic может не распознать сложные изменения автоматически (например, изменение типа столбца). В таком случае придётся вручную редактировать файл миграции. Это нормально — просто будьте внимательны.
Пример использования в реальном проекте
Представьте, что вы работаете над крупным проектом e-commerce. Здесь базы данных меняются постоянно: добавляются новые модели, модифицируются существующие. Миграции помогают вам поддерживать синхронность между моделями и базой данных, даже если над проектом работает несколько команд.
Кроме того, откат миграций спасёт вас в случае необходимости быстрого восстановления, если что-то пойдёт не так. Например, вы добавили колонку и быстро поняли, что она не нужна (или хуже: сломала продакшен). С Alembic откат изменений — это несколько секунд, а не часы работы.
Теперь вы уверенно можете изменять структуру базы данных через Alembic, и это станет вашим незаменимым инструментом в дальнейшей работе. На следующих лекциях мы углубимся в управление версиями и интеграцию Alembic в более сложные проекты.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ