Przeprowadziłem migrację, która dodała nową tabelę i chcę ją przywrócić i usunąć migrację bez tworzenia nowej migracji.
Jak mam to zrobić? Czy istnieje polecenie cofnięcia ostatniej migracji, a następnie mogę po prostu usunąć plik migracji?
Przeprowadziłem migrację, która dodała nową tabelę i chcę ją przywrócić i usunąć migrację bez tworzenia nowej migracji.
Jak mam to zrobić? Czy istnieje polecenie cofnięcia ostatniej migracji, a następnie mogę po prostu usunąć plik migracji?
Odpowiedzi:
Możesz przywrócić, migrując do poprzedniej migracji.
Na przykład, jeśli dwie ostatnie migracje to:
0010_previous_migration
0011_migration_to_revert
Następnie zrobiłbyś:
./manage.py migrate my_app 0010_previous_migration
Następnie możesz usunąć migrację 0011_migration_to_revert
.
Jeśli używasz Django 1.8+, możesz wyświetlać nazwy wszystkich migracji za pomocą
./manage.py showmigrations my_app
Aby cofnąć wszystkie migracje aplikacji, możesz uruchomić:
./manage.py migrate my_app zero
'0010_previous_migration'
, nie wiem, dlaczego widziałbyś to zachowanie.
Odpowiedź Alasdair obejmuje podstawy
./manage.py showmigrations
migrate
za pomocą nazwy aplikacji i nazwy migracjiNależy jednak zauważyć, że nie wszystkie migracje można odwrócić. Dzieje się tak, jeśli Django nie ma reguły umożliwiającej odwrócenie. W przypadku większości zmian, za pomocą których migracje były automatycznie wprowadzane ./manage.py makemigrations
, cofnięcie będzie możliwe. Jednak skrypty niestandardowe będą musiały mieć napisane zarówno do przodu, jak i do tyłu, jak opisano w przykładzie tutaj:
https://docs.djangoproject.com/en/1.9/ref/migration-operations/
Jeśli miałeś RunPython
operację, być może chcesz po prostu wycofać migrację bez pisania logicznie rygorystycznego skryptu cofania. Pozwala na to szybki hack do przykładu z dokumentów (powyższy link), pozostawiając bazę danych w takim samym stanie, w jakim była po zastosowaniu migracji, nawet po jej cofnięciu.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).bulk_create([
Country(name="USA", code="us"),
Country(name="France", code="fr"),
])
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(forwards_func, lambda apps, schema_editor: None),
]
Działa to dla Django 1.8, 1.9
Aktualizacja: Lepszym sposobem na piśmie, to byłoby zastąpienie lambda apps, schema_editor: None
ze migrations.RunPython.noop
w powyższym fragmencie. Oba są funkcjonalnie tym samym. (podziękowania dla komentarzy)
RunPython.noop
zamiast wbudowanej lambda lub ekwiwalentu: docs.djangoproject.com/en/1.8/ref/migration-operations/…
migrations.RunPython(forwards_func, migrations.RunPython.noop)
. Musisz to sprawdzić funkcjonalnie. To powinno kiedyś zostać dodane jako odpowiedź lub edycja.
Oto moje rozwiązanie, ponieważ powyższe rozwiązanie tak naprawdę nie obejmuje przypadku użycia, gdy używasz RunPython
.
Dostęp do tabeli można uzyskać poprzez ORM za pomocą
from django.db.migrations.recorder import MigrationRecorder
>>> MigrationRecorder.Migration.objects.all()
>>> MigrationRecorder.Migration.objects.latest('id')
Out[5]: <Migration: Migration 0050_auto_20170603_1814 for model>
>>> MigrationRecorder.Migration.objects.latest('id').delete()
Out[4]: (1, {u'migrations.Migration': 1})
Możesz więc wyszukiwać w tabelach i usuwać te wpisy, które są dla Ciebie odpowiednie. W ten sposób możesz szczegółowo modyfikować. W przypadku RynPython
migracji musisz także dbać o dane, które zostały dodane / zmienione / usunięte. Powyższy przykład pokazuje tylko, w jaki sposób uzyskujesz dostęp do tabeli za pomocą Djang ORM.
django.db.utils.ProgrammingError: relation "<relation name>" already exists
o migrate --fake
błędzie, więc zrobiłem błąd, więc próbowałem wrócić, ale psycopg2.ProgrammingError: relation "<other <relation name>" does not exist
DZIĘKI
Inną rzeczą, którą możesz zrobić, to usunąć tabelę utworzoną ręcznie.
Oprócz tego będziesz musiał usunąć ten konkretny plik migracji. Będziesz także musiał usunąć ten konkretny wpis z tabeli migracji django (prawdopodobnie ostatni w twoim przypadku), który koreluje z tą konkretną migracją.
Nie usuwaj pliku migracji, dopóki nie zostanie przywrócone. Popełniłem ten błąd i bez pliku migracji baza danych nie wiedziała, co należy usunąć.
python manage.py showmigrations
python manage.py migrate {app name from show migrations} {00##_migration file.py}
Usuń plik migracji. Gdy pożądana migracja znajdzie się w Twoich modelach ...
python manage.py makemigrations
python manage.py migrate
Zrobiłem to w wersji 1.9.1 (aby usunąć ostatnią lub najnowszą utworzoną migrację):
rm <appname>/migrations/<migration #>*
przykład: rm myapp/migrations/0011*
zalogowałem się do bazy danych i uruchomiłem ten SQL (postgres w tym przykładzie)
delete from django_migrations where name like '0011%';
Byłem wtedy w stanie utworzyć nowe migracje, które zaczęły się od właśnie usuniętego numeru migracji (w tym przypadku 11).
Ta odpowiedź dotyczy podobnych przypadków, jeśli najlepsza odpowiedź Alasdair nie pomaga . (Na przykład, jeśli niechciana migracja jest tworzona wkrótce przy każdej nowej migracji lub jeśli jest w większej migracji, której nie można przywrócić lub tabela została usunięta ręcznie.)
... usunąć migrację bez tworzenia nowej migracji?
TL; DR : Możesz usunąć kilka ostatnio cofniętych (zdezorientowanych) migracji i utworzyć nową po naprawieniu modeli . Możesz także użyć innych metod, aby skonfigurować go tak, aby nie tworzył tabeli za pomocą polecenia migrowania. Ostatnia migracja musi zostać utworzona, aby pasowała do aktualnych modeli .
Przypadki, dla których nikt nie chce tworzyć tabeli dla modelu, który musi istnieć:
A) Żadna taka tabela nie powinna istnieć w żadnej bazie danych na żadnym komputerze i żadnych warunkach
class Meta: abstract = True
B) Tabela jest tworzona rzadko, przez coś innego lub ręcznie w specjalny sposób.
class Meta: managed = False
C) Tabela jest używana tylko na niektórych komputerach (np. W fazie rozwoju).
class Meta: managed = some_switch
.D) Projekt wykorzystuje wiele baz danych wsettings.DATABASES
allow_migrate
, aby rozróżnić bazy danych, w których należy utworzyć tabelę, a gdzie nie.Migracja jest tworzona we wszystkich przypadkach A), B), C), D) za pomocą Django 1.9+ (i tylko w przypadkach B, C, D z Django 1.8), ale jest stosowana do bazy danych tylko w odpowiednich przypadkach, a może nigdy, jeśli wymagane tak. Migracje były niezbędne do uruchomienia testów od wersji Django 1.8. Całkowity odpowiedni aktualny stan jest rejestrowany przez migracje, nawet dla modeli z parametrem manage = False w Django 1.9+, aby możliwe było utworzenie klucza obcego między modelami zarządzanymi / niezarządzanymi lub sprawienie, by model zarządzany = True później. (To pytanie zostało napisane w czasie Django 1.8. Wszystko tutaj powinno być ważne dla wersji od 1.8 do obecnej wersji 2.2.)
Jeśli ostatniej migracji nie da się łatwo przywrócić, możliwe jest ostrożne (po utworzeniu kopii zapasowej bazy danych) wykonanie fałszywego przywrócenia ./manage.py migrate --fake my_app 0010_previous_migration
, ręczne usunięcie tabeli.
W razie potrzeby utwórz stałą migrację ze stałego modelu i zastosuj ją bez zmiany struktury bazy danych ./manage.py migrate --fake my_app 0011_fixed_migration
.
Jeśli masz problemy z przywracaniem migracji i w jakiś sposób ją pomieszałeś, możesz przeprowadzić fake
migrację.
./manage.py migrate <name> --ignore-ghost-migrations --merge --fake
W przypadku wersji django <1.7 spowoduje to utworzenie wpisu w south_migrationhistory
tabeli, musisz go usunąć.
Teraz możesz łatwo cofnąć migrację.
PS: Utknąłem przez długi czas i przeprowadzanie fałszywej migracji, a następnie cofanie się pomogło mi.