Como simplificar as migrações no Django 1.7?

92

Já existem perguntas semelhantes para South, mas eu comecei meu projeto com Django 1.7 e não estou usando South.

Durante o desenvolvimento, muitas migrações foram criadas, no entanto, o software ainda não foi entregue e não existe nenhum banco de dados que deva ser migrado. Portanto, gostaria de redefinir as migrações como se meu modelo atual fosse o original e recriar todos os bancos de dados.

Qual é a forma recomendada de fazer isso?

EDIT: A partir do Django 1.8, há um novo comando chamado squashmigrations que mais ou menos resolve o problema descrito aqui.

Kit Fisto
fonte
O que significa redefinir uma migração? Desfazer?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respostas:

137

Eu tenho esse. Acabei de descobrir isso e é bom.

  • Primeiro, para limpar a tabela de migrações:

    ./manage.py migrate --fake <app-name> zero
  • Remova a app-name/migrations/pasta ou conteúdo.

  • Faça as migrações:

    ./manage.py makemigrations <app-name>
  • Por fim, organize suas migrações sem fazer outras alterações no banco de dados:

    ./manage.py migrate --fake <app-name>
kzorro
fonte
5
Esta é uma boa resposta. Apenas excluir as migrações não desfaz nenhum dano que as migrações com falhas causaram. Isso realmente limpa o quadro e permite que você recomece.
rogueleaderr
15
Se você elaborar um pouco, esta deve ser a resposta aceita.
tani-rokk
8
Ótima resposta de uma linha, irmão, não tenho ideia do que isso faz
bischoffingston
13
Esta linha simplesmente inverte as migrações uma a uma, até zero. Para o sistema de migração Django, <app-name> agora é um novo aplicativo e makemigrations <app-name>começará a partir 0001. --fakeevita que as tabelas sejam realmente modificadas, que as migrações só devem ser marcadas como reversas e não aplicadas ao esquema. (Adicionando pequenas explicações para fins de integridade, @ tani-rokk, @Fabrizio)
Mir Nazim,
17
manage.py migrate --fake <app-name> zeropara limpar a tabela de migrações e, em seguida, remova <app-name> / migrations / pasta ou conteúdo. Então manage.py makemigrations <app-name>e finalmente faça manage.py migrate --fake <app-name>. Isso organizará suas migrações sem fazer outras alterações no banco de dados.
doeke
36

Na versão de migrações do Django 1.7, a funcionalidade de redefinição que costumava ser no Sul foi descartada em favor de uma nova funcionalidade para 'esmagar' suas migrações. Essa é uma boa maneira de manter o número de migrações sob controle.

https://docs.djangoproject.com/en/dev/topics/migrations/#squashing-migrations

Se você ainda quiser realmente começar do zero, suponho que ainda possa esvaziar a tabela de migrações e remover as migrações, após o que você executaria makemigrationsnovamente.

Tijs
fonte
2
Como eu "removeria as migrações" além de esvaziar a tabela de migrações? Eu removeria a pasta inteira ou apenas os arquivos 00X _ *. Py?
Kit Fisto de
com o Sul, você pode remover a pasta de migrações que seria recriada ao executar o makemigrations novamente. Presumo que funcione da mesma forma para Django 1.7
tijs
4
Apenas uma nota. no Django 1.7, se você, sem cuidado, excluir a pasta de migração, poderá gerar uma exceção se seu modelo for filho de outroraise KeyError("Migration %s dependencies reference nonexistent parent node %r" % (migration, parent))
Algoritmático
Especificamente ./manage.py squashmigrations myapp 0004, esmagará todas as migrações antes da migração 0004em seu aplicativo myapp. Isso criará uma única migração comprimida.
Bryce Guinta de
22

Eu simplesmente tive o mesmo problema. Aqui está minha solução alternativa.

#!/bin/sh
echo "Starting ..."

echo ">> Deleting old migrations"
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc"  -delete


# Optional
echo ">> Deleting database"
find . -name "db.sqlite3" -delete

echo ">> Running manage.py makemigrations"
python manage.py makemigrations

echo ">> Running manage.py migrate"
python manage.py migrate

echo ">> Done"

O findcomando: http://unixhelp.ed.ac.uk/CGI/man-cgi?find

Abdelhamid Belarbi
fonte
13
isso exclui os dados, não apenas as migrações
hobs
2
você deve excluir os arquivos .pyc também
shalbafzadeh
7

Supondo que esta seja a estrutura do seu projeto,

project_root/
    app1/
        migrations/
    app2/
        migrations/
    ...
    manage.py
    remove_migrations.py

você pode executar o script remove_migrations.py do local indicado acima para excluir todos os arquivos de migração.

#remove_migrations.py
"""
Run this file from a Django =1.7 project root. 
Removes all migration files from all apps in a project.
""" 
from unipath import Path

this_file = Path(__file__).absolute()
current_dir = this_file.parent
dir_list = current_dir.listdir()

for paths in dir_list:
    migration_folder = paths.child('migrations')
    if migration_folder.exists():
        list_files = migration_folder.listdir()
        for files in list_files:
            split = files.components()
            if split[-1] != Path('__init__.py'):
                files.remove()

A exclusão manual pode ser cansativa se você tiver um projeto elaborado. Isso me economizou muito tempo. Excluir arquivos de migração é seguro. Já fiz isso uma enésima série de vezes sem enfrentar quaisquer problemas ... ainda.

No entanto, quando apaguei a pasta de migrações makemigrationsou migratenão criei a pasta de volta para mim. O script garante que a pasta de migração com a sua __init__.pypermaneça no lugar, apenas excluindo os arquivos de migração.


fonte
você poderia simplesmente deletar as pastas de migração e recriá-las com um init .py vazio (por exemplo touch migrations/__init__.py)
hobs
6
  1. Excluir arquivos: delete_migrations.py (na raiz de prj):
import os

for root, dirs, files in os.walk(".", topdown=False):
  for name in files:
      if '/migrations' in root and name != '__init__.py':
          os.remove(os.path.join(root, name))
  1. DELETE FROM django_migrations Where app in ('app1', 'app2');

  2. ./manage.py makemigrations

  3. ./manage.py migrate --fake

OU, você pode escrever a migração de tudo isso

Ibrohim Ermatov
fonte
Tive de especificar os nomes dos aplicativos para ./manage.py makemigrationsfuncionar, assim:./manage.py makemigrations orders alerts
Salami
4

Tento comandos diferentes e algumas das respostas me ajudam. Somente esta sequência no meu caso corrigiu as dependências quebradas nas migrações no MYAPP e limpou todas as migrações anteriores começando do zero.

Antes de fazer isso, certifique-se de que o banco de dados já esteja sincronizado (por exemplo, não adicione um novo campo de modelo aqui ou altere as opções de Meta).

rm -Rf MYAPP/migrations/*
python manage.py makemigrations --empty MYAPP
python manage.py makemigrations
python manage.py migrate --fake MYAPP 0002

Onde 0002 é o número de migração retornado pelo último comando makemigrations.

Agora você pode executar makemigrations / migrate novamente normalmente porque a migração 0002 está armazenada, mas não é refletida no banco de dados já sincronizado.

chirale
fonte
De todas as soluções mencionadas acima, apenas esta funcionou para mim sem falhas e sem excluir o banco de dados.
Vivek Jha
3

Se você não se preocupa com as migrações anteriores, que tal remover apenas todas as migrações do diretório / migrações? você vai começar a sequência de migração do zero, tomando seu modelo atual como referência, como se você tivesse escrito o modelo inteiro agora.

Se você não confia em mim o suficiente para removê-los, tente movê-los para longe.

vokimon
fonte
Qual é o significado de manter antigas migrações? Minhas perguntas acertam o solo quando se tenta atualizar do Django 1.6 para 1.8.
Jay Modi
As migrações são simplesmente um registro das mudanças que você fez no banco de dados. Eu segui o conselho do vokiman mais de uma vez quando minha cadeia de migração para de funcionar.
Adam Starrh
1

Uma maneira simples é

Vá para cada aplicativo e exclua os arquivos de migração.

Em seguida, vá para a tabela django-migrtaions no banco de dados e trunque-a (exclua todas as entradas).

Depois disso, você pode criar migrações novamente.

sprksh
fonte
1
ao excluir arquivos de migração, certifique-se de não excluir os arquivos init .
Sprksh
Isso realmente me ajudou. Eu apaguei todas as migrações, eliminei as tabelas do meu banco de dados sqlite, mas ainda não consegui fazer migrações ... entretanto, uma vez que restaurei os arquivos _init_ .py (doh), fui capaz de fazer migrações novamente e começar a navegar. @sprksh = Salva-vidas!
twknab
0

cd para diretório src cd /path/to/src

deletar diretórios de migração rm -rf your_app/migrations/

observe que isso deve ser feito para cada aplicativo separadamente

migrar python3.3 manage.py migrate

se você deseja começar de novo python3.3 manage.py makemigrations your_app

Pato de borracha
fonte
0

Se você está em modo de desenvolvimento e deseja apenas resetar tudo (banco de dados, migrações, etc), utilizo este script baseado na resposta de Abdelhamid Ba. Isso limpará as tabelas do banco de dados (Postgres), excluirá todos os arquivos de migração, executará novamente as migrações e carregará meus acessórios iniciais:

#!/usr/bin/env bash
echo "This will wipe out the database, delete migration files, make and apply migrations and load the intial fixtures."

while true; do
    read -p "Do you wish to continue?" yn
    case $yn in
        [Yy]* ) make install; break;;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
    esac
done

echo ">> Deleting old migrations"
find ../../src -path "*/migrations/*.py" -not -name "__init__.py" -delete

# Optional
echo ">> Deleting database"
psql -U db_user -d db_name -a -f ./reset-db.sql

echo ">> Running manage.py makemigrations and migrate"
./migrations.sh

echo ">> Loading initial fixtures"
./load_initial_fixtures.sh

echo ">> Done"

arquivo reset-db.sql:

DO $$ DECLARE
    r RECORD;
BEGIN
    -- if the schema you operate on is not "current", you will want to
    -- replace current_schema() in query with 'schematodeletetablesfrom'
    -- *and* update the generate 'DROP...' accordingly.
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
        EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
    END LOOP;
END $$;

arquivo migration.sh:

#!/usr/bin/env bash
cd ../../src
./manage.py makemigrations
./manage.py migrate

arquivo load_initial_fixtures.sh:

#!/usr/bin/env bash
cd ../../src
./manage.py loaddata ~/path-to-fixture/fixture.json

Apenas certifique-se de alterar os caminhos que correspondem ao seu aplicativo. Eu pessoalmente tenho esses scripts em uma pasta chamada project_root / script / local, e os fontes do django estão em project_root / src.

mrmuggles
fonte
0

Depois de excluir cada pasta de "migrações" em meu aplicativo (manualmente), executei:

./manage.py dbshell
delete from django_migrations;

Então eu pensei que poderia apenas fazer ./manage.py makemigrationspara regenerar todos eles. No entanto, nenhuma alteração foi detectada. Em seguida, tentei especificar um aplicativo por vez: ./manage.py makemigrations foo, ./manage.py makemigrations bar. No entanto, isso resultou em dependências circulares que não puderam ser resolvidas.

Por fim, executei um único comando makemigrations que especificou TODOS os meus aplicativos (sem nenhuma ordem específica):

./manage.py makemigrations foo bar bike orange banana etc

Desta vez, funcionou - as dependências circulares foram resolvidas automaticamente (ele criou arquivos de migração adicionais quando necessário).

Então consegui fugir ./manage.py migrate --fakee voltei ao negócio.

shacker
fonte