Problemas com migrações

Neste artigo vamos falar sobre migrações no Web2py.

Todos sabemos que o W2P faz proezas com a DAL mas as vezes temos alguns percalços no caminho.

Para fazer o controle do estado das migrações é criado por padrão na pasta databases alguns arquivos com a extensão '.table'.

Esses arquivos são responsáveis por armazenar o estado atual da tabela e logo eles são modificados quando fazemos alterações na definição de tabela no código python.

De fato esses arquivos são muito úteis porém há momentos em que eles começam a dar problemas.

Primeiro de tudo vamos começar mudando nosso código na função define_table passando um argumento migrate='nome_tabela.table'.

db.define_table('tabela1',
    Field('nome_campo''string'),
    migrate='tabela1.table'
)

Isso fará com que o arquivo .table da tabela1 contenha seu nome, isso facilita evita aqueles arquivos redundantes no diretório.

O próximo passo é entender como funcionam as migrações do construtor DAL.

Isso foi retirado da docstring da pydal do Web2py (gluon.packages.base.py).

migrate: sets default migrate behavior for all tables
fake_migrate: sets default fake_migrate behavior for all tables
migrate_enabled: If set to False disables ALL migrations
fake_migrate_all: If set to True fake migrates ALL tables

migrate: Determina a migração padrão para todas as tabelas se True, no nosso caso estamos usando um migrate customizado em nosso define_table, então pode alterá-lo para False.

fake_migrate: Ele utiliza o padrão False, ele será usado para tratar migrações individuais em bancos de dados legados.

migrate_enabled: Habilita as migrações, seu padrão é True.

fake_migrate_all: É utilizado em bancos legados e atribui um tratamento padrão para todas as tabelas.

db = DAL(myconf.get("db.uri"),
        pool_size=10,
        migrate_enabled=myconf.get('db.migrate_enabled'), # True
        fake_migrate=myconf.get('db.fake_migrate'), # False
        fake_migrate_all=myconf.get('db.fake_migrate_all'), # False
        migrate=myconf.get('db.migrate'), # False
        check_reserved=['all'])

O exemplo acima seria a configuração padrão para criar um banco de dados do zero. Ou seja ele iria criar as tabelas para nós utilizando um .table customizado.

Caso ele retorne algum erro de cara, execute a aplicação quantas vezes precisar até que ele crie todas as tabelas e arquivos.

NOTA: Muito cuidado com campos notnull=True geralmente eles não são criados por exigirem sempre um valor padrão, então o notnull=True deve vir acompanhado de um default='anyway'.

<class 'gluon.contrib.pg8000.ProgrammingError'> ('ERRO', '23502', 'valor nulo na coluna "colunaXYZ" viola a restrição não-nula')


Em bases Legadas ou estruturas já criadas

Haverão casos onde precisamos lidar com estruturas legadas ou já criadas, nesse caso podem haver problemas como:

<class 'gluon.contrib.pg8000.ProgrammingError'> ('ERRO', '42701', 'coluna "colunaXYZ" da relação "tableZYX" já existe')


A solução padrão para este caso é apagar todos os arquivos '.table' e o arquivo sql.log.
Feito isso devemos setar como True o parâmetro fake_migrate_all e executarmos nosso app até atualizar o banco.
db = DAL(myconf.get("db.uri"),
        pool_size=10,
        migrate_enabled=myconf.get('db.migrate_enabled'), # True
        fake_migrate=myconf.get('db.fake_migrate'), # False
        fake_migrate_all=myconf.get('db.fake_migrate_all'), # True
        migrate=myconf.get('db.migrate'), # False
        check_reserved=['all'])

Depois retorne o parâmetro fake_migrate_all para False.


Espero ter sanado as duvidas dos novatos por que ninguém merece perder todo um dia de trabalho fazendo migrações manuais na base de dados.💀


Comentários

Postagens mais visitadas deste blog

Configurar o web2py no Apache e Ubuntu LTS

Limpando a sujeira para fazer backup

Recursive select with web2py