Миграция данных с использованием Alembic

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

Предположим, имеется таблица vinyl, в которой хранится информация о виниловых пластинках музыкальных групп, в том числе Guns N' Roses. Совершенствуя приложение, вы пришли к выводу, чтобы было бы здорово добавить в таблицу поле, определяющее, является ли пластинка студийным альбомом. Вы заранее знаете названия студийных альбомов и хотели бы, чтобы Alembic их отметил — установил значение is_studio=True.

Файл миграции может выглядеть следующим образом:

from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import table

STUDIO_ALBUMS = (
    "Appetite for Destruction",
    "G N' R Lies",
    "Use Your Illusion I",  
    "Use Your Illusion II",
    "The Spaghetti Incident?",
    "Chinese Democracy"
)

def upgrade():
    op.add_column(
        'vinyl',
        sa.Column('is_studio',
                  sa.Boolean(),
                  nullable=False,
                  server_default=sa.false()))

    vinyl = table(
        'vinyl',
        sa.Column('name', sa.VARCHAR(length=128)),
        sa.Column('is_studio', sa.Boolean())
    )
    op.execute(
        vinyl
            .update()
            .where(vinyl.c.name.in_(STUDIO_ALBUMS))
            .values({'is_studio': True})
    )

def downgrade():
    op.drop_column('vinyl', 'is_studio')

Код выше в первую очередь добавляет в таблицу vinyl поле is_studio с логическим значением False по умолчанию (см. аргумент server_default), при этом пустые значения не допускаются. Далее для пластинок, названия которых входят в кортеж STUDIO_ALBUMS, поле is_studio принимает значение True.

Аналогичным образом можно обновлять и переносить и другие данные.