Planuję zmienić nazwy kilku modeli w istniejącym projekcie Django, w którym istnieje wiele innych modeli, które mają relacje klucza obcego z modelami, które chciałbym zmienić. Jestem prawie pewien, że będzie to wymagało wielu migracji, ale nie jestem pewien dokładnej procedury.
Powiedzmy, że zacznę od następujących modeli w aplikacji Django o nazwie myapp
:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
Chcę zmienić nazwę Foo
modelu, ponieważ nazwa tak naprawdę nie ma sensu i powoduje zamieszanie w kodzie i Bar
sprawiłaby, że nazwa byłaby znacznie jaśniejsza.
Z tego, co przeczytałem w dokumentacji deweloperskiej Django, przyjmuję następującą strategię migracji:
Krok 1
Modyfikuj models.py
:
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_ridonkulous = models.BooleanField()
Zwróć uwagę, że AnotherModel
nazwa pola foo
nie zmienia się, ale relacja jest aktualizowana doBar
modelu. Moje rozumowanie jest takie, że nie powinienem zmieniać zbyt wiele na raz i że gdybym zmienił nazwę tego pola na bar
, ryzykowałbym utratę danych w tej kolumnie.
Krok 2
Utwórz pustą migrację:
python manage.py makemigrations --empty myapp
Krok 3
Edytuj Migration
klasę w pliku migracji utworzonym w kroku 2, aby dodać RenameModel
operację do listy operacji:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
Krok 4
Zastosuj migrację:
python manage.py migrate
Krok 5
Edytuj powiązane nazwy pól w models.py
:
class Bar(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_ridonkulous = models.BooleanField()
Krok 6
Utwórz kolejną pustą migrację:
python manage.py makemigrations --empty myapp
Krok 7
Edytuj Migration
klasę w pliku migracji utworzonym w kroku 6, aby dodać RenameField
operację (e) dla wszystkich powiązanych nazw pól do listy operacji:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_fields'), # <-- is this okay?
]
operations = [
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Krok 8
Zastosuj drugą migrację:
python manage.py migrate
Oprócz aktualizacji reszty kodu (widoków, formularzy itp.) W celu odzwierciedlenia nowych nazw zmiennych, czy w zasadzie tak będzie działać nowa funkcja migracji?
Wydaje się również, że jest to wiele kroków. Czy można w jakiś sposób skondensować operacje migracyjne?
Dzięki!
źródło
apps.get_model
w nich. zajęło mi dużo czasu, żeby to rozgryźć../manage.py makemigrations myapp
polecenie zapyta Cię, czy zmieniłeś nazwę swojego modelu. Np .: Czy zmieniłeś nazwę modelu myapp.Foo na Bar? [t / N] Jeśli odpowiesz „t”, migracja będzie zawierała temigration.RenameModel('Foo', 'Bar')
same liczby dla pól o zmienionychmanage.py makemigrations myapp
może nadal się nie powieść: „Może być konieczne ręczne dodanie tego elementu, jeśli zmienisz nazwę modelu i kilka jego pól naraz; dla autodetektora będzie to wyglądać tak, jakbyś usunął model ze starą nazwą i dodał nowy z inną nazwę, a utworzona migracja spowoduje utratę wszystkich danych ze starej tabeli ”. Django 2.1 Docs Dla mnie wystarczyło stworzyć pustą migrację, dodać do niej przemianowania modelu, a następnie uruchomićmakemigrations
jak zwykle.Początkowo myślałem, że metoda Piątka zadziałała, ponieważ migracja działała dobrze do kroku 4. Jednak niejawne zmiany „ForeignKeyField (Foo)” na „ForeignKeyField (Bar)” nie były powiązane z żadną migracją. Dlatego migracja nie powiodła się, gdy chciałem zmienić nazwy pól relacji (krok 5-8). Może to wynikać z faktu, że moje „AnotherModel” i „YetAnotherModel” są wysyłane w innych aplikacjach w moim przypadku.
Więc udało mi się zmienić nazwy moich modeli i pól relacji, wykonując poniższe czynności:
Zaadaptowałem metodę z tego, a szczególnie sztuczkę otranzera.
Więc tak jak Fiver, powiedzmy, że mamy w myapp :
A w myotherapp :
Krok 1:
Przekształć każdy OneToOneField (Foo) lub ForeignKeyField (Foo) na IntegerField (). (To zachowa identyfikator powiązanego obiektu Foo jako wartość pola całkowitego).
Następnie
Krok 2: (Podobnie jak krok 2-4 z Piątki)
Zmień nazwę modelu
Utwórz pustą migrację:
Następnie edytuj jak:
Ostatecznie
Krok 3:
Przekształć swoje IntegerField () w ich poprzedni ForeignKeyField lub OneToOneField, ale z nowym modelem słupkowym. (Poprzednie pole całkowite przechowywało identyfikator, więc django to zrozumie i przywróć połączenie, co jest fajne.)
Następnie wykonaj:
Co bardzo ważne, na tym etapie musisz zmodyfikować każdą nową migrację i dodać zależność od migracji RenameModel Foo-> Bar. Jeśli więc zarówno AnotherModel, jak i YetAnotherModel znajdują się w myotherapp, utworzona migracja w myotherapp musi wyglądać następująco:
Następnie
Krok 4:
Ostatecznie możesz zmienić nazwy swoich pól
a następnie wykonaj automatyczną zmianę nazwy
(django powinien zapytać, czy faktycznie zmieniłeś nazwę modelu, powiedz tak)
I to wszystko!
Działa to na Django1.8
źródło
IntegerField
. To działało idealnie dla mnie i ma tę dodatkową zaletę, że są odtwarzane z poprawną nazwą. Oczywiście radziłbym przejrzeć wszystkie migracje przed ich uruchomieniem!ForeignKey
s naIntegerField
uratowała mi dzisiaj dzień!Musiałem zrobić to samo i podążać. Od razu zmieniłem model (kroki 1 i 5 razem z odpowiedzi Piątka). Następnie utworzył migrację schematu, ale zmodyfikował go tak:
To działało doskonale. Wszystkie moje istniejące dane pokazały się, wszystkie inne tabele wskazywały na Bar w porządku.
stąd: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
źródło
W przypadku Django 1.10 udało mi się zmienić dwie nazwy klas modeli (w tym ForeignKey i dane), po prostu uruchamiając Makemigrations, a następnie Migrate dla aplikacji. Na etapie Makemigrations musiałem potwierdzić, że chcę zmienić nazwy tabel. Migracja bez problemu zmieniła nazwy tabel.
Następnie zmieniłem nazwę pola ForeignKey na zgodne i ponownie zostałem poproszony przez Makemigrations o potwierdzenie, że chcę zmienić nazwę. Przeprowadź migrację niż dokonaj zmiany.
Zrobiłem to w dwóch krokach bez specjalnej edycji plików. Na początku dostałem błędy, ponieważ zapomniałem zmienić plik admin.py, o czym wspomniał @wasibigeek.
źródło
Zmierzyłem się również z problemem, który opisał v.thorey i stwierdziłem, że jego podejście jest bardzo przydatne, ale można je skondensować na mniejszą liczbę kroków, które są w rzeczywistości krokami od 5 do 8, jak opisał Piątka, bez kroków od 1 do 4, z wyjątkiem tego, że krok 7 musi zostać zmieniony jako mój poniżej kroku 3. Ogólne kroki są następujące:
Krok 1: Edytuj powiązane nazwy pól w models.py
Krok 2: Utwórz pustą migrację
Krok 3: Edytuj klasę migracji w pliku migracji utworzonym w kroku 2
Krok 4: Zastosuj migrację
Gotowe
PS Próbowałem tego podejścia w Django 1.9
źródło
Używam Django w wersji 1.9.4
Wykonałem następujące kroki: -
Właśnie zmieniłem nazwę modelu oldName na NewName Run
python manage.py makemigrations
. Poprosi Cię oDid you rename the appname.oldName model to NewName? [y/N]
wybranie YBiegnij
python manage.py migrate
i zapyta cię oNastępujące typy zawartości są nieaktualne i należy je usunąć:
Wszelkie obiekty powiązane z tymi typami zawartości za pomocą klucza obcego również zostaną usunięte. Czy na pewno chcesz usunąć te typy zawartości? Jeśli nie masz pewności, odpowiedz „nie”.
Zmienia nazwę i migruje wszystkie istniejące dane do nowej nazwanej tabeli.
źródło
Niestety napotkałem problemy (każdy django 1.x) z migracją zmiany nazwy, która pozostawia stare nazwy tabel w bazie danych.
Django nawet nie próbuje niczego na starym stole, po prostu zmień nazwę swojego modelu. Ten sam problem z kluczami obcymi i ogólnie indeksami - zmiany tam nie są poprawnie śledzone przez Django.
Najprostsze rozwiązanie (obejście):
Prawdziwe rozwiązanie (łatwy sposób na zmianę wszystkich indeksów, ograniczeń, wyzwalaczy, nazw itp. W 2 zatwierdzeniach, ale raczej w przypadku mniejszych tabel):
zatwierdzenie A:
Bar
. (w tym wszystkie relacje na schemacie)W migracji przygotuj
RunPython
, które skopiują dane z Foo do Bar (w tymid
z Foo)zatwierdzenie B: (bez pośpiechu, zrób to, gdy cały zespół jest migrowany)
Foo
dalsze porządki:
błąd w Django:
źródło
Chciałem tylko potwierdzić i dodać komentarz ceasaro. Wydaje się, że Django 2.0 robi to teraz automatycznie.
Jestem na Django 2.2.1, wszystko co musiałem zrobić, żeby zmienić nazwę modelu i uruchomić
makemigrations
.Tutaj pyta, czy zmieniłem nazwę określonej klasy z
A
naB
, wybrałem tak i uruchomiłem migrację i wszystko wydaje się działać.Uwaga: Nie zmieniłem nazwy starej nazwy modelu w żadnym pliku w folderze projektu / migracji.
źródło
Musiałem zmienić nazwy kilku tabel. Ale tylko jedna zmiana nazwy modelu została zauważona przez Django. Stało się tak, ponieważ Django iteruje nad dodanymi, a następnie usuniętymi modelami. Dla każdej pary sprawdza, czy należą do tej samej aplikacji i mają identyczne pola . Tylko jedna tabela nie miała kluczy obcych do tabel do zmiany nazwy (klucze obce zawierają nazwę klasy modelu, jak pamiętasz). Innymi słowy, tylko jedna tabela nie miała żadnych zmian pól. Dlatego został zauważony.
Tak więc rozwiązaniem jest zmiana nazwy jednej tabeli na raz
models.py
, prawdopodobnie zmiana nazwy klasy modelu wviews.py
i wykonanie migracji. Następnie sprawdź kod pod kątem innych odniesień (nazw klas modeli, nazw pokrewnych (zapytań), nazw zmiennych). W razie potrzeby przeprowadź migrację. Następnie opcjonalnie połącz wszystkie te migracje w jedną (pamiętaj również o skopiowaniu importu).źródło
Zrobiłbym @ceasaro słowa, moje w jego komentarzu do tej odpowiedzi .
Nowsze wersje Django mogą wykrywać zmiany i pytać o to, co zostało zrobione. Dodałbym też, że Django może mieszać kolejność wykonywania niektórych poleceń migracji.
To byłoby mądre, aby zastosować niewielkie zmiany i uruchom
makemigrations
imigrate
jeśli wystąpi błąd w pliku migracji mogą być edytowane.Aby uniknąć błędów, można zmienić kolejność wykonywania niektórych wierszy.
źródło
migrations.SeparateDatabaseAndState
może pomóc?Jeśli używasz dobrego IDE, takiego jak PyCharm, możesz kliknąć prawym przyciskiem myszy nazwę modelu i wykonać refaktoryzację -> zmień nazwę. Oszczędza to kłopotów z przejściem przez cały kod, który odwołuje się do modelu. Następnie uruchom makemigrations i dokonaj migracji. Django 2+ po prostu potwierdzi zmianę nazwy.
źródło
Zaktualizowałem Django z wersji 10 do wersji 11:
(
-U
dla „upgrade”) i rozwiązało problem.źródło