Qual é a abordagem recomendada para redefinir o histórico de migração usando o Django South?

153

Eu acumulei algumas migrações usando o South (0.7) e o Django (1.1.2), que estão começando a consumir bastante tempo em meus testes de unidade. Gostaria de redefinir a linha de base e iniciar um novo conjunto de migrações. Analisei a documentação do Sul , fiz a pesquisa usual do Google / Stackoverflow (por exemplo, "django sul (redefinir ou excluir ou remover) histórico de migração") e não encontrei nada óbvio.

Uma abordagem que eu contemplava envolvia "recomeçar" removendo "Sul" ou "limpando" o histórico manualmente (por exemplo, limpe a tabela db, remova arquivos de migração do diretor de migrações) e apenas execute novamente,

./manage.py schemamigration southtut --initial

Portanto, se alguém já fez isso antes e tem algumas dicas / sugestões, seria muito apreciado.

Glenn Snyder
fonte
às vezes você precisa adicionar manualmente __init__.pyaappname/migrations
laike9m
2
Como você redefine as migrações no 1.7 (com a migração interna)?
Timo
1
@Timo: docs.djangoproject.com/en/dev/topics/migrations/… poderia ser uma abordagem. Você também pode simplesmente remover suas migrações / diretórios e re-edição ./manage.py makemigrations, mas as coisas ruins vão acontecer se você não começar a partir de um db fresco ...
Jocelyn DELALANDE
Eu acho que squashmigrationsé a resposta certa
Julio Marins

Respostas:

121

EDIT - Estou colocando um comentário abaixo no topo, pois é importante lê-lo antes da> resposta aceita que se segue @andybak

@ Dominique: Seus conselhos sobre o reset do manage.py para o sul são perigosos e podem destruir o banco de dados se houver aplicativos de terceiros usando o sul no projeto, conforme apontado por @thnee abaixo. Como sua resposta tem tantos votos positivos, eu realmente apreciaria se você pudesse editá-la e adicionar pelo menos um aviso sobre isso, ou (melhor ainda) alterá-la para refletir a abordagem @hobs (que é tão conveniente quanto não é) afetar outros aplicativos) - obrigado! O que você achou?

A resposta aceita segue abaixo:

Primeiro, uma resposta do autor sul :

Desde que você tome cuidado em fazer isso em todas as implantações simultaneamente, não deve haver nenhum problema com isso. Pessoalmente, eu faria:

    rm -r appname/migrations/ 
    ./manage.py reset south 
    ./manage.py convert_to_south appname 

(Observe que a reset southparte " " limpa os registros de migração para TODOS os aplicativos, portanto, execute as outras duas linhas para todos os aplicativos ou exclua seletivamente).

A convert_to_southchamada no final faz uma nova migração e a aplica de forma falsa (já que seu banco de dados já possui as tabelas correspondentes). Não há necessidade de descartar todas as tabelas de aplicativos durante o processo.

Aqui está o que estou fazendo no meu servidor de produção dev + quando preciso me livrar de todas essas migrações desnecessárias de desenvolvedores:

  1. Verifique se temos o mesmo esquema de banco de dados nos dois lados
  2. exclua todas as pastas de migração dos dois lados
  3. execute ./manage.py redefinir o sul (como diz a postagem) em ambos os lados = limpa a tabela sul *
  4. execute ./manage.py convert_to_south nos dois lados (falsificando a migração 0001)
  5. então posso reiniciar para fazer migrações e enviar as pastas de migrações no meu servidor

* exceto se você deseja limpar apenas um aplicativo entre outros, caso seja necessário, edite sua tabela south_history e exclua apenas as entradas do seu aplicativo.

Dominique Guardiola
fonte
2
Apenas para constar, a resposta do autor do sul foi a seguinte: Contanto que você faça isso em todas as implantações simultaneamente, não deve haver nenhum problema com isso. Pessoalmente, eu faria: rm -r appname / migrations / ./manage.py redefinir sul ./manage.py convert_to_south appname (Observe que a parte "redefinir sul" limpa os registros de migração para TODOS os aplicativos, portanto, execute as outras duas linhas para todos os aplicativos ou excluir seletivamente).
Adriaan Tijsseling
2
Observe também que, se você soltar as tabelas, precisará em manage.py schemamigration app name --initialvez de convert_to_south.
Adriaan Tijsseling
7
No Django 1.5, o comando de gerenciamento "reset" desapareceu. Em vez disso, você vai querer fazer algo parecido south.models.MigrationHistory.objects.all().delete().
Andrew B.
13
@ Dominique: Seus conselhos manage.py reset southsão perigosos e podem destruir o banco de dados se houver aplicativos de terceiros usando o sul no projeto, conforme apontado por @ thnee abaixo. Como sua resposta tem tantos votos positivos, eu realmente apreciaria se você pudesse editá-la e adicionar pelo menos um aviso sobre isso, ou (melhor ainda) alterá-la para refletir a abordagem @hobs (que é tão conveniente quanto não é) afetar outros aplicativos) - obrigado!
ChrisV
3
Por que isso foi tão votado? Você NUNCA deve excluir quase completamente sua tabela south_migrationhistory. Isso estragaria completamente todos os aplicativos dependentes com migrações que você não deseja tocar. A resposta de Hob é a correta.
Cerin
188

Se você precisar redefinir seletivamente (para apenas um aplicativo) as migrações que estão demorando muito, isso funcionou para mim.

rm <app-dir>/migrations/*
python manage.py schemamigration <app-name> --initial
python manage.py migrate <app-name> 0001 --fake  --delete-ghost-migrations

Não se esqueça de restaurar manualmente as dependências de outros aplicativos adicionando linhas como o depends_on = (("<other_app_name>", "0001_initial"),("<yet_another_app_name>", "0001_initial"))seu <app-dir>/migrations/0001_initial.pyarquivo, como o primeiro atributo na sua classe de migração logo abaixo class Migration(SchemaMigration):.

Você pode, então, ./manage.py migrate <app-name> --fake --delete-ghost-migrationsem outros ambientes, de acordo com essa resposta do SO . Obviamente, se você falsificar a exclusão ou a falsificação, migrate zeroprecisará excluir manualmente quaisquer tabelas de banco de dados restantes com uma migração como essa .

Uma opção mais nuclear é ./manage.py migrate --fake --delete-ghost-migrationsno servidor de implantação ao vivo, seguido por um [my] sqldump. Em seguida, canalize esse dump no [my] sql nos ambientes em que você precisa do banco de dados migrado e totalmente preenchido. Sei que o sacrilégio sul, mas funcionou para mim.

fogão
fonte
2
O que eu realmente quero é "levar o models.py como evangelho e me deixar limpo a partir desse ponto". Mantendo assim a capacidade de configurar uma implantação do zero ou trabalhar a partir de uma implantação existente.
Bryce
1
É o que isso faz.
Placas
2
Eu estava demorando um DependsOnUnknownMigrationpouco para fingir a nova migração inicial. Graças ao seu comentário, eu pude descobrir que devo atualizar a depends_ondeclaração sempre que ela se referir a este aplicativo. Esta é realmente a melhor resposta aqui. Obrigado! :)
manu
55

Graças às respostas de Dominique Guardiola e fogão, isso me ajudou a resolver um problema difícil. No entanto, existem alguns problemas com a solução, aqui está minha opinião.

Usar nãomanage.py reset south é uma boa ideia se você tiver aplicativos de terceiros que usam o Sul, por exemplo django-cms(basicamente tudo usa o Sul).

reset south excluirá todo o histórico de migração de todos os aplicativos que você instalou.

Agora considere que você atualiza para a versão mais recente do django-cms, ela conterá novas migrações como 0009_do_something.py. O Sul certamente ficará confuso quando você tentar executar essa migração sem 0001passar 0008no histórico de migração.

É muito melhor / mais seguro redefinir seletivamente apenas os aplicativos que você está mantendo .


Primeiro, verifique se seus aplicativos não têm dessincronização entre migrações em disco e migrações que foram executadas no banco de dados. Caso contrário, haverá dor de cabeça.

1. Excluir histórico de migração para meus aplicativos

sql> delete from south_migrationhistory where app_name = 'my_app';

2. Excluir migrações para meus aplicativos

$ rm -rf my_app/migrations/

3. Crie novas migrações iniciais para meus aplicativos

$ ./manage.py schemamigration --initial my_app

4. Execute falsamente as migrações iniciais para meus aplicativos

Isso insere as migrações south_migrationhistorysem tocar nas tabelas reais:

$ ./manage.py migrate --fake my_app

As etapas 3 e 4 são na verdade apenas uma variante mais longa manage.py convert_to_south my_app, mas eu prefiro esse controle extra, em situações delicadas como modificar o banco de dados de produção.

thnee
fonte
2
Editei minha resposta para incorporar correções para os problemas encontrados (apenas adivinhando-os com base em sua resposta) e testei em um banco de dados de produção com milhões de linhas.
Placas
2
É praticamente o que estamos fazendo. Se você usar a opção --delete-ghost-migrations na etapa 4, poderá excluir a etapa 1.
tokench
Você deve especificar explicitamente os nomes dos aplicativos ./manage.py migrate --fakese não desejar migrar outros aplicativos com migração pendente.
Wadim
2
@wadim Daí a etapa 0: "verifique se não há dessincronização entre migrações no disco e migrações que foram executadas no banco de dados".
thnee
@thnee Certo. Provavelmente vale a pena mencionar que você está se referindo a todos os aplicativos instalados na etapa 0. Você conhece uma maneira fácil de executar a etapa 0?
Wadim 28/11
7

Como em seguida (veja a resposta dela), estamos usando uma abordagem mais suave à sugestão do autor do sul (Andrew Godwin) citada em outro lugar aqui e estamos separando o que fazemos com a base de código do que fazemos com o banco de dados, durante a implantação , porque precisamos que as implantações sejam repetíveis:

O que fazemos no código:

# Remove all the migrations from the app
$ rm -fR appname/migrations
# Make the first migration (don't touch the database)
$ ./manage.py schemamigration appname --initial

O que fazemos no banco de dados após a implantação desse código

# Fake the migration history, wiping out the rest
$ ./manage.py migrate appname --fake --delete-ghost-migrations
tobych
fonte
Eu acho que fiz a mesma coisa, mas excluindo manualmente as entradas do banco de dados, em vez de usar --delete_ghoist-migrations. Seu caminho é um pouco melhor.
Wobily_col
1

Se você está apenas trabalhando na máquina dev, escrevi um comando de gerenciamento que faz praticamente o que Dominique sugeriu.

http://balzerg.blogspot.co.il/2012/09/django-app-reset-with-south.html

Ao contrário da sugestão do autor sul, isso NÃO prejudicará outros aplicativos instalados usando o sul.

idanzalz
fonte
E se, diferentemente do autor, você deseja manter as migrações existentes (por exemplo, deseja redefinir o aplicativo e o histórico de migração, mas mantém as migrações reais), tente: goo.gl/0ZnWm
mgalgs
1

A seguir, apenas se você deseja redefinir todos os aplicativos. Faça backup de todos os seus bancos de dados antes desse trabalho. Anote também sua dependência nos arquivos iniciais, se houver.

De uma vez:

(1) find . -type d -name migrations -exec git rm -rf '{}' \;
(2) find . -type d -name migrations -exec rm -rf '{}' \;
(3) ./manage.py schemamigration <APP_NAME> --initial
(4) [GIT COMMIT]

Teste a inicialização do seu projeto antes do envio por push. Em seguida, para cada máquina local / remota, aplique o seguinte:

(5) [GIT PULL]
(6) ./manage.py reset south
(7) ./manage.py migrate --fake

Faça inicial (3) para cada aplicativo que você deseja envolver novamente. Observe que, o reset (6) excluirá apenas o histórico de migração, portanto, não é prejudicial para as bibliotecas. Migrações falsas (7) recuperam o histórico de migração de qualquer aplicativo de terceiros instalado.

yasc
fonte
0

excluir o arquivo necessário da pasta do aplicativo

caminho da instância

 cd /usr/local/lib/python2.7/dist-packages/wiki/south_migrations

wiki -é meu aplicativo

Andrei Eremchuk
fonte