Alembic + SQLAlchemy + PostgreSQL (Docker) | Мини‑курс [3]
0. Исходная точка (важно)
Перед этим уроком у вас уже должна быть применена первая миграция (таблица users создана):
alembic current
alembic history
alembic current показывает ревизию первой миграции (или уже head, если вы ранее делали урок 3). В БД есть таблицы users и alembic_version.1. Создаем вторую миграцию
Для примера мы меняем схему: добавляем колонку full_name в users. Сначала меняем модель, затем создаем миграцию через --autogenerate.
1.1. Меняем модель
Откройте app/models.py и добавьте поле:
from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column
from app.db import Base
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False)
# Новая колонка (для учебного примера допускаем NULL)
full_name: Mapped[str | None] = mapped_column(String(200), nullable=True)
Почему nullable=True: таблица уже существует и может содержать строки. Новая колонка без значения по умолчанию и с nullable=False часто приводит к ошибке (БД потребует заполнить значение для существующих строк).
1.2. Генерируем файл второй миграции
alembic revision --autogenerate -m "add full_name to users"
После команды в папке alembic/versions/ появится новый файл, например:
alembic/versions/2b1c3d4e5f6a_add_full_name_to_users.py
1.3. Проверяем содержимое миграции
Внутри должно быть что-то похожее:
from alembic import op
import sqlalchemy as sa
def upgrade() -> None:
op.add_column("users", sa.Column("full_name", sa.String(length=200), nullable=True))
def downgrade() -> None:
op.drop_column("users", "full_name")
down_revision будет указывать на первую миграцию. Это “цепочка” миграций.2. Применяем вторую миграцию
Применить все миграции до последней (включая вторую):
alembic upgrade head
2.1. Проверяем, что колонка появилась
docker exec -it alembic_course_db psql -U app_user -d app_db
\d users
\q
users есть колонка full_name.2.2. Проверяем, что текущая версия — head
alembic current
3. Откат второй миграции
Здесь два способа: откат на один шаг -1 или откат до конкретной ревизии. Для второй миграции чаще всего используют -1.
3.1. Откат на один шаг назад
alembic downgrade -1
Что произойдет: Alembic возьмет последнюю примененную миграцию (вторую) и выполнит ее downgrade(), то есть удалит колонку full_name.
3.2. Проверяем, что откат сработал
docker exec -it alembic_course_db psql -U app_user -d app_db
\d users
\q
full_name снова нет. alembic current показывает ревизию первой миграции.alembic current
3.3. Откат до конкретной ревизии (альтернатива)
Посмотреть историю:
alembic history
Откатиться до ID первой миграции (пример):
alembic downgrade 7f3b9b1e0f2a
ID у вас будет другим — используйте свой из alembic history.
4. Повторно применяем вторую миграцию
Вернуться вперед снова:
alembic upgrade head
Проверить:
docker exec -it alembic_course_db psql -U app_user -d app_db
\d users
\q
full_name снова на месте.5. Возвращение к “нулевому состоянию”
В терминах Alembic “нулевое состояние” — это base, то есть состояние до первой миграции. Это не “очистка данных”, а именно откат схемы по миграциям.
5.1. Откатить всё до base
alembic downgrade base
5.2. Что в итоге будет в БД
- таблица
usersбудет удалена (потому что первая миграция при откате делаетop.drop_table("users")) - таблица
alembic_versionможет остаться, но будет указывать на отсутствие версии (поведение зависит от версии/настроек; обычно запись версии очищается)
5.3. Проверка
docker exec -it alembic_course_db psql -U app_user -d app_db
\dt
\q
downgrade base удаляет таблицы, созданные миграциями. Для учебной БД это нормально. Для продакшена — делать только при полной уверенности и наличии бэкапа.5.4. Вернуться из “нуля” обратно к актуальному состоянию
alembic upgrade head
users и добавлена колонка full_name (если обе миграции существуют).6. “Удаление второй миграции”: что это значит на практике
Сценарий A: миграция еще НЕ применялась нигде (безопаснее)
- Удалите файл второй миграции из
alembic/versions/. - Убедитесь, что БД не ушла вперед:
alembic currentдолжен показывать первую миграцию. - Если вы уже применили вторую миграцию локально — сначала откатите:
alembic downgrade -1 - После этого можно удалить файл миграции и создать новый корректный.
Сценарий B: миграция уже применена в общей среде/у коллег (опасно)
Если миграция уже “уехала” в общий репозиторий и была применена на другой БД, то удалять файл миграции нельзя, потому что история схемы станет “дырявой”. Правильный путь — создать новую миграцию, которая исправит/отменит изменения.
7. Команды для контроля: где мы в миграциях
| Команда | Зачем |
|---|---|
alembic history |
Посмотреть всю цепочку миграций (ID и сообщения). |
alembic current |
Узнать, какая миграция применена сейчас. |
alembic upgrade head |
Дойти до последней миграции. |
alembic downgrade -1 |
Откатить одну миграцию назад (для “второй миграции” — самый типичный шаг). |
alembic downgrade base |
Откатить всё в “ноль” (до первой миграции). |
Ссылки по теме
- Alembic + SQLAlchemy + PostgreSQL (Docker) | Мини‑курс [1]
- Alembic + SQLAlchemy + PostgreSQL (Docker) | Мини‑курс [2]
- Alembic + SQLAlchemy + PostgreSQL (Docker) | Ошибки | Мини‑курс [4]
![Alembic + SQLAlchemy + PostgreSQL (Docker) | Мини‑курс [3] Alembic + SQLAlchemy + PostgreSQL (Docker) | Мини‑курс [3]](https://technobee.ru/media/zoo/images/line100_python_b25cc4f165b72ffa38afe4daaa46eb87.png)
![Alembic + SQLAlchemy + PostgreSQL (Docker) | Мини‑курс [3] Alembic + SQLAlchemy + PostgreSQL (Docker) | Мини‑курс [3]](https://technobee.ru/media/zoo/images/line100_python_24f065d5f44b128d7987e916e0a668ad.png)