DEV Community

Cover image for Alembic: Versionamento de Banco de Dados (Parte 2)
Carine Neris
Carine Neris

Posted on

Alembic: Versionamento de Banco de Dados (Parte 2)

Na Parte 1 deste artigo, aprendemos um pouco sobre os fundamentos do Alembic, como inicializar o ambiente de migração e como criar migrações manuais. Agora, vamos elevar o nível e descobrir como automatizar esse processo e como lidar com bancos de dados que já possuem dados e tabelas.

Automatizando Migrações com --autogenerate

Um dos recursos mais poderosos do Alembic é a sua capacidade de detectar automaticamente as mudanças nos seus modelos SQLAlchemy e gerar os scripts de migração correspondentes. Isso economiza tempo e reduz erros humanos ao escrever DDL manualmente.

1. Configurando o target_metadata

Para que o recurso de autogeração funcione, o Alembic precisa saber onde encontrar a definição dos seus modelos (o objeto MetaData). Isso é configurado no arquivo migrations/env.py.

Localize a variável target_metadata e importe o seu objeto Base.metadata (ou equivalente):

# migrations/env.py

# Importe o seu objeto Base ou os seus modelos
from my_app.models import Base 

# ...

# Defina o target_metadata
target_metadata = Base.metadata

# ...
Enter fullscreen mode Exit fullscreen mode

Dica: Certifique-se de que todos os seus modelos foram importados antes de definir o target_metadata, caso contrário, o Alembic não conseguirá detectá-los.

2. Gerando a Migração Automática

Com o target_metadata configurado, você pode usar a flag --autogenerate ao criar uma nova revisão:

alembic revision --autogenerate -m "add_profile_column_to_users"
Enter fullscreen mode Exit fullscreen mode

O Alembic irá comparar o estado atual do banco de dados com a definição nos seus modelos SQLAlchemy e gerará automaticamente as funções upgrade() e downgrade() com as alterações detectadas (ex: op.add_column, op.create_table).

Atenção: Sempre revise o arquivo gerado! O Alembic é excelente, mas algumas mudanças complexas (como renomear colunas) podem exigir ajustes manuais no script gerado[1].


Começando com um Banco de Dados Existente

Um cenário muito comum é querer introduzir o Alembic em um projeto que já está em andamento e possui um banco de dados populado com tabelas. Se você simplesmente rodar upgrade head, o Alembic tentará criar tabelas que já existem, resultando em erro.

Para resolver isso, usamos o processo de Baselining[2].

Passo 1: Criar a Migração de "Estado Zero"

Primeiro, gere uma migração que represente o estado atual do seu banco de dados:

alembic revision --autogenerate -m "baseline_initial_state"
Enter fullscreen mode Exit fullscreen mode

Se seus modelos SQLAlchemy estiverem em sincronia com o banco de dados atual, o script gerado pode vir quase vazio. Se houver discrepâncias, ele conterá os comandos para criar as tabelas existentes.

Passo 2: O Comando stamp

Em vez de executar essa migração (que falharia ao tentar criar o que já existe), você deve dizer ao Alembic que o banco de dados já está naquela versão. Para isso, usamos o comando stamp:

alembic stamp head
Enter fullscreen mode Exit fullscreen mode

O comando stamp cria a tabela alembic_version no seu banco de dados e insere o ID da revisão mais recente (o head), sem executar nenhum código de migração. A partir deste momento, o Alembic "sabe" onde o banco está e você pode começar a criar novas migrações normalmente para as próximas alterações.


Melhores Práticas e Arquitetura

Ao trabalhar com Alembic e SQLAlchemy Core, considere estas diretrizes para manter uma arquitetura de banco de dados saudável:

Prática Descrição
Scripts Atômicos Cada migração deve focar em uma única alteração lógica (ex: adicionar uma tabela ou um conjunto de colunas relacionadas).
Teste de Downgrade Sempre teste se o comando downgrade funciona corretamente para evitar ficar "preso" em uma versão quebrada.
Integração no CI/CD Automatize o comando alembic upgrade head no seu pipeline de deploy para garantir que o banco de dados esteja sempre sincronizado com o código.
Cuidado com Dados Migrações DDL alteram estrutura. Se precisar migrar dados (ex: transformar uma string em um JSON), você pode usar op.execute() dentro do script de migração.

Conclusão

O Alembic transforma o gerenciamento de banco de dados de uma tarefa manual e arriscada em um processo versionado e automatizado. Seja começando um projeto do zero ou organizando um legado, ele é a ferramenta indispensável para qualquer desenvolvedor Python que preza por agilidade e segurança na arquitetura de dados.


Referências

[1] Alembic Autogenerate Guide: https://alembic.sqlalchemy.org/en/latest/autogenerate.html
[2] Handling Existing Databases with Alembic: https://alembic.sqlalchemy.org/en/latest/tutorial.html#stamping-the-database

Top comments (0)