Jak uprościć migracje w Django 1.7?

92

Są już podobne pytania dla South, ale zacząłem projekt z Django 1.7 i nie używam South.

W trakcie opracowywania powstało wiele migracji, jednak oprogramowanie nie zostało jeszcze dostarczone i nie ma bazy danych, którą należy migrować. Dlatego chciałbym zresetować migracje tak, jakby mój obecny model był oryginalnym i odtworzyć wszystkie bazy danych.

Jaki jest zalecany sposób, aby to zrobić?

EDYCJA: Od Django 1.8 jest nowe polecenie o nazwie squashmigrations, które w mniejszym lub większym stopniu rozwiązuje opisany tutaj problem.

Kit Fisto
źródło
Co to znaczy zresetować migrację? Cofnij to?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

137

Mam to. Właśnie to rozgryzłem i jest dobrze.

  • Po pierwsze, aby wyczyścić tabelę migracji:

    ./manage.py migrate --fake <app-name> zero
    
  • Usuń app-name/migrations/folder lub zawartość.

  • Wykonaj migracje:

    ./manage.py makemigrations <app-name>
    
  • Wreszcie uporządkuj migracje bez wprowadzania innych zmian w bazie danych:

    ./manage.py migrate --fake <app-name>
    
kzorro
źródło
5
To jest dobra odpowiedź. Samo usunięcie migracji nie cofa żadnych uszkodzeń spowodowanych przez błędne migracje. To faktycznie czyści łupek i pozwala zacząć od nowa.
rogueleaderr
15
Jeśli chcesz trochę rozwinąć, to powinna być akceptowana odpowiedź.
tani-rokk
8
Świetna odpowiedź w jednej linii brachu, nie mam pojęcia, co to robi
bischoffingston
13
Ta linia po prostu odwraca migracje jedna po drugiej, aż zero. Dla systemu migracji Django <app-name> jest teraz nową aplikacją i makemigrations <app-name>zacznie się od 0001. --fakezapobiega faktycznej modyfikacji tabel, że migracje powinny być oznaczane tylko jako odwrócone, a nie faktycznie stosowane do schematu. (Dodając drobne wyjaśnienia ze względu na kompletność, @ tani-rokk, @Fabrizio)
Mir Nazim
17
manage.py migrate --fake <app-name> zeroaby wyczyścić tabelę migracji, a następnie usuń <nazwa aplikacji> / migrations / folder lub zawartość. Wtedy manage.py makemigrations <app-name>i na koniec zrób manage.py migrate --fake <app-name>. Spowoduje to uporządkowanie migracji bez wprowadzania innych zmian w bazie danych.
doeke
36

W wersji migracji Django 1.7 funkcja resetowania, która wcześniej znajdowała się na południu, została porzucona na rzecz nowej funkcji do „zgniatania” migracji. Ma to być dobry sposób na kontrolowanie liczby migracji.

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

Jeśli nadal chcesz naprawdę zacząć od zera, zakładam, że nadal możesz, opróżniając tabelę migracji i usuwając migracje, po czym uruchomisz je makemigrationsponownie.

tijs
źródło
2
Jak mógłbym „usunąć migracje” poza opróżnieniem tabeli migracji? Czy usunąłbym cały folder, czy tylko pliki 00X _ *. Py?
Kit Fisto
z South można usunąć folder migracji, który zostałby utworzony ponownie po ponownym uruchomieniu makemigrations. Zakładam, że to działa tak samo dla Django 1.7
tijs
4
Tylko uwaga. w Django 1.7, jeśli nie ostrożnie usuniesz folder migracji, może to spowodować wyjątek, jeśli twój model jest dzieckiem innegoraise KeyError("Migration %s dependencies reference nonexistent parent node %r" % (migration, parent))
Algorithmatic
W szczególności ograniczy ./manage.py squashmigrations myapp 0004wszystkie migracje przed migracją 0004w aplikacji myapp. Spowoduje to utworzenie pojedynczej zgniecionej migracji.
Bryce Guinta
22

Po prostu miałem ten sam problem. Oto moje obejście.

#!/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"

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

Abdelhamid Belarbi
źródło
13
spowoduje to usunięcie danych, a nie tylko migracji
trwa
2
powinieneś również usunąć pliki .pyc
shalbafzadeh
7

Zakładając, że to jest struktura Twojego projektu,

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

możesz uruchomić skrypt remove_migrations.py z miejsca wskazanego powyżej, aby usunąć wszystkie pliki migracji.

#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()

Ręczne usuwanie może być męczące, jeśli masz rozbudowany projekt. To zaoszczędziło mi dużo czasu. Usuwanie plików migracji jest bezpieczne. Robiłem to dziesiątą liczbę razy bez żadnych problemów ... jeszcze.

Jednak kiedy usunąłem folder migracji makemigrationslub migratenie utworzyłem go z powrotem za siebie. Skrypt upewnia się, że folder migracji __init__.pypozostaje na swoim miejscu, usuwając tylko pliki migracji.


źródło
możesz po prostu usunąć foldery migracji i odtworzyć je z pustym plikiem init .py (np. touch migrations/__init__.py)
hobs
6
  1. Usuń pliki: delete_migrations.py (w katalogu głównym 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

LUB możesz napisać migrację z tego wszystkiego

Ibrohim Ermatov
źródło
Musiałem określić nazwy aplikacji ./manage.py makemigrationsdo pracy, na przykład:./manage.py makemigrations orders alerts
Salami
4

Wypróbowuję różne polecenia i niektóre odpowiedzi mi pomagają. Tylko ta sekwencja w moim przypadku naprawiła zarówno uszkodzone zależności w migracjach w MYAPP, jak i wyczyściła wszystkie poprzednie migracje, zaczynając od zera.

Zanim to zrobisz, upewnij się, że baza danych jest już zsynchronizowana (np. Nie dodawaj tutaj nowego pola Model ani nie zmieniaj opcji Meta).

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

Gdzie 0002 to numer migracji zwrócony przez ostatnie polecenie makemigrations.

Teraz możesz normalnie uruchomić makemigrations / migrate, ponieważ migracja 0002 jest przechowywana, ale nie jest odzwierciedlona w już zsynchronizowanej bazie danych.

chirale
źródło
Ze wszystkich wyżej wymienionych rozwiązań tylko to działało u mnie bez błędu i bez usuwania bazy danych.
Vivek Jha
3

Jeśli nie interesują Cię poprzednie migracje, co z usunięciem wszystkich migracji w katalogu migrations /? rozpoczniesz sekwencję migracji od zera, biorąc bieżący model jako odniesienie, tak jakbyś teraz napisał cały model.

Jeśli nie ufasz mi na tyle, by je usunąć, spróbuj zamiast tego je odsunąć.

vokimon
źródło
Jakie jest znaczenie utrzymania starych migracji? Moje pytania padają na ziemię, gdy ktoś próbuje zaktualizować django z 1.6 do 1.8.
Jay Modi
Migracje to po prostu zapis zmian dokonanych w bazie danych. Skorzystałem z rady vokimana więcej niż raz, kiedy mój łańcuch migracji przestał działać.
Adam Starrh,
1

Prosty sposób to

Przejdź do każdej aplikacji i usuń pliki migracji.

Następnie przejdź do tabeli django-migrtaions w bazie danych i skróć ją (usuń wszystkie wpisy).

Następnie możesz ponownie utworzyć migracje.

sprksh
źródło
1
podczas usuwania plików migracji upewnij się, że nie usuwasz plików init .
sprksh
To naprawdę mi pomogło. Usunąłem wszystkie migracje, usunąłem tabele z mojej bazy danych sqlite, ale nadal nie byłem w stanie wykonać migracji ... jednak po przywróceniu plików _init_ .py (doh) mogłem ponownie przeprowadzić migrację i zacząć działać. @sprksh = Lifesaver!
twknab
0

cd do katalogu src cd /path/to/src

usuń katalogi migracji rm -rf your_app/migrations/

pamiętaj, że należy to zrobić osobno dla każdej aplikacji

migrować python3.3 manage.py migrate

jeśli chcesz zacząć od nowa python3.3 manage.py makemigrations your_app

Gumowa kaczuszka
źródło
0

Jeśli jesteś w trybie programistycznym i chcesz po prostu zresetować wszystko (bazę danych, migracje itp.), Używam tego skryptu w oparciu o odpowiedź Abdelhamida Ba. Spowoduje to wyczyszczenie tabel bazy danych (Postgres), usunięcie wszystkich plików migracji, ponowne uruchomienie migracji i załadowanie moich początkowych urządzeń:

#!/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"

plik 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 $$;

plik migracji.sh:

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

load_initial_fixtures.sh plik:

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

Po prostu pamiętaj, aby zmienić ścieżki na odpowiadające Twojej aplikacji. Osobiście mam te skrypty w folderze o nazwie project_root / script / local, a źródła django znajdują się w project_root / src.

mrmuggles
źródło
0

Po usunięciu każdego folderu „migracje” w mojej aplikacji (ręcznie) wykonałem:

./manage.py dbshell
delete from django_migrations;

Wtedy pomyślałem, że mogę po prostu ./manage.py makemigrationszregenerować je wszystkie. Jednak nie wykryto żadnych zmian. Następnie próbowałem określić jedną aplikację naraz: ./manage.py makemigrations foo, ./manage.py makemigrations bar. Jednak spowodowało to zależności cykliczne, których nie można było rozwiązać.

Na koniec uruchomiłem jedno polecenie makemigrations, które określiło WSZYSTKIE moje aplikacje (w dowolnej kolejności):

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

Tym razem zadziałało - zależności cykliczne zostały automatycznie rozwiązane (w razie potrzeby utworzono dodatkowe pliki migracji).

Wtedy mogłem biec ./manage.py migrate --fake i wróciłem do biznesu.

shacker
źródło