Ich plane, mehrere Modelle in einem vorhandenen Django-Projekt umzubenennen, in dem es viele andere Modelle gibt, die Fremdschlüsselbeziehungen zu den Modellen haben, die ich umbenennen möchte. Ich bin mir ziemlich sicher, dass dies mehrere Migrationen erfordert, bin mir aber nicht sicher, wie genau das vorgehen soll.
Angenommen, ich beginne mit den folgenden Modellen in einer Django-App namens 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()
Ich möchte das Foo
Modell umbenennen , da der Name nicht wirklich sinnvoll ist und Verwirrung im Code verursacht und Bar
zu einem viel klareren Namen führen würde.
Nach dem, was ich in der Django-Entwicklungsdokumentation gelesen habe, gehe ich von der folgenden Migrationsstrategie aus:
Schritt 1
Ändern 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()
Beachten Sie, dass sich der AnotherModel
Feldname für foo
nicht ändert, die Beziehung zum Bar
Modell jedoch aktualisiert wird . Meine Argumentation ist, dass ich nicht zu viel auf einmal ändern sollte und dass bar
ich das Risiko eingehen würde, die Daten in dieser Spalte zu verlieren , wenn ich diesen Feldnamen in ändere .
Schritt 2
Erstellen Sie eine leere Migration:
python manage.py makemigrations --empty myapp
Schritt 3
Bearbeiten Sie die Migration
Klasse in der in Schritt 2 erstellten Migrationsdatei, um die RenameModel
Operation zur Operationsliste hinzuzufügen :
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
Schritt 4
Wenden Sie die Migration an:
python manage.py migrate
Schritt 5
Bearbeiten Sie die zugehörigen Feldnamen in 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()
Schritt 6
Erstellen Sie eine weitere leere Migration:
python manage.py makemigrations --empty myapp
Schritt 7
Bearbeiten Sie die Migration
Klasse in der in Schritt 6 erstellten Migrationsdatei, um die RenameField
Operation (en) für alle zugehörigen Feldnamen zur Operationsliste hinzuzufügen :
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_fields'), # <-- is this okay?
]
operations = [
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Schritt 8
Wenden Sie die 2. Migration an:
python manage.py migrate
Abgesehen davon, dass der Rest des Codes (Ansichten, Formulare usw.) aktualisiert wird, um die neuen Variablennamen wiederzugeben, würde die neue Migrationsfunktionalität im Grunde so funktionieren?
Auch dies scheint eine Menge Schritte zu sein. Können die Migrationsvorgänge auf irgendeine Weise komprimiert werden?
Vielen Dank!
quelle
apps.get_model
sie verwenden. Ich habe viel Zeit gebraucht, um das herauszufinden../manage.py makemigrations myapp
Befehl gefragt, ob Sie Ihr Modell umbenannt haben. Beispiel: Haben Sie das myapp.Foo-Modell in Bar umbenannt? [j / N] Wenn Sie mit "y" antworten , enthält Ihre Migration diemigration.RenameModel('Foo', 'Bar')
gleichen Zählungen für die umbenannten Felder :-)manage.py makemigrations myapp
Möglicherweise schlägt dies immer noch fehl: "Möglicherweise müssen Sie dies manuell hinzufügen, wenn Sie den Namen des Modells und einige seiner Felder gleichzeitig ändern. Für den Autodetektor sieht es so aus, als hätten Sie ein Modell mit dem alten Namen gelöscht und ein neues mit hinzugefügt Ein anderer Name und die von ihm erstellte Migration verlieren alle Daten in der alten Tabelle. " Django 2.1 Docs Für mich war es ausreichend, eine leere Migration zu erstellen, die Modellumbenennungen hinzuzufügen und dannmakemigrations
wie gewohnt auszuführen .Zuerst dachte ich, dass Fivers Methode für mich funktioniert, da die Migration bis Schritt 4 gut funktioniert hat. Die impliziten Änderungen von 'ForeignKeyField (Foo)' in 'ForeignKeyField (Bar)' waren jedoch in keiner Migration verwandt. Aus diesem Grund ist die Migration fehlgeschlagen, als ich Beziehungsfelder umbenennen wollte (Schritt 5-8). Dies könnte daran liegen, dass mein "AnotherModel" und "YetAnotherModel" in meinem Fall in anderen Apps versendet werden.
Daher konnte ich meine Modelle und Beziehungsfelder wie folgt umbenennen:
Ich habe die Methode daraus und insbesondere den Trick des Otranzers angepasst.
Nehmen wir also wie Fiver an, wir haben in myapp :
Und in myotherapp :
Schritt 1:
Transformiere jedes OneToOneField (Foo) oder ForeignKeyField (Foo) in IntegerField (). (Dadurch bleibt die ID des zugehörigen Foo-Objekts als Wert des Ganzzahlfelds erhalten.)
Dann
Schritt 2: (Wie Schritt 2-4 von Fiver)
Ändern Sie den Modellnamen
Erstellen Sie eine leere Migration:
Dann bearbeiten Sie es wie folgt:
Schließlich
Schritt 3:
Verwandeln Sie Ihr IntegerField () in das vorherige ForeignKeyField oder OneToOneField, jedoch mit dem neuen Balkenmodell. (Das vorherige Integer-Feld hat die ID gespeichert, also versteht Django das und stellt die Verbindung wieder her, was cool ist.)
Dann mach:
Sehr wichtig ist, dass Sie in diesem Schritt alle neuen Migrationen ändern und die Abhängigkeit von den Migrationen von RenameModel Foo-> Bar hinzufügen müssen. Wenn sich also AnotherModel und YetAnotherModel in myotherapp befinden, muss die in myotherapp erstellte Migration folgendermaßen aussehen:
Dann
Schritt 4:
Schließlich können Sie Ihre Felder umbenennen
und dann automatisch umbenennen
(django sollte dich fragen, ob du den modelnamen tatsächlich umbenannt hast, sag ja)
Und das ist es!
Dies funktioniert auf Django1.8
quelle
IntegerField
. Dies hat bei mir perfekt funktioniert und hat den zusätzlichen Vorteil, dass sie mit dem richtigen Namen neu erstellt werden. Natürlich würde ich empfehlen, alle Migrationen zu überprüfen, bevor sie tatsächlich ausgeführt werden!ForeignKey
s zuIntegerField
s hat mir heute den Tag gerettet!Ich musste das Gleiche tun und folgen. Ich habe das Modell auf einmal geändert (Schritte 1 und 5 zusammen aus Fivers Antwort). Anschließend wurde eine Schemamigration erstellt, diese jedoch wie folgt bearbeitet:
Das hat perfekt funktioniert. Alle meine vorhandenen Daten wurden angezeigt, alle anderen Tabellen, auf die verwiesen wurde, waren in Ordnung.
von hier: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
quelle
Für Django 1.10 gelang es mir, zwei Modellklassennamen (einschließlich eines ForeignKey und mit Daten) zu ändern, indem ich einfach Makemigrations ausführte und dann für die App migrierte. Für den Schritt Makemigrations musste ich bestätigen, dass ich die Tabellennamen ändern wollte. Migrate hat die Namen der Tabellen problemlos geändert.
Dann habe ich den Namen des ForeignKey-Felds entsprechend geändert und wurde erneut von Makemigrations gebeten, zu bestätigen, dass ich den Namen ändern wollte. Migrieren als die Änderung vorgenommen.
Also habe ich dies in zwei Schritten ohne spezielle Dateibearbeitung gemacht. Ich habe zuerst Fehler erhalten, weil ich vergessen habe, die Datei admin.py zu ändern, wie von @wasibigeek erwähnt.
quelle
Ich habe mich auch dem Problem gestellt, wie v.thorey beschrieben hat, und festgestellt, dass sein Ansatz sehr nützlich ist, aber in weniger Schritte zusammengefasst werden kann, die tatsächlich die Schritte 5 bis 8 sind, wie Fiver ohne Schritt 1 bis 4 beschrieben hat, außer dass Schritt 7 als mein geändert werden muss unter Schritt 3. Die allgemeinen Schritte sind wie folgt:
Schritt 1: Bearbeiten Sie die zugehörigen Feldnamen in models.py
Schritt 2: Erstellen Sie eine leere Migration
Schritt 3: Bearbeiten Sie die Migrationsklasse in der in Schritt 2 erstellten Migrationsdatei
Schritt 4: Wenden Sie die Migration an
Getan
PS Ich habe diesen Ansatz auf Django 1.9 ausprobiert
quelle
Ich benutze Django Version 1.9.4
Ich habe die folgenden Schritte befolgt: -
Ich habe gerade das Modell oldName in NewName Run umbenannt
python manage.py makemigrations
. Sie werden aufgefordertDid you rename the appname.oldName model to NewName? [y/N]
, Y auszuwählenLaufen Sie
python manage.py migrate
und es wird Sie fragenDie folgenden Inhaltstypen sind veraltet und müssen gelöscht werden:
Alle Objekte, die durch einen Fremdschlüssel mit diesen Inhaltstypen verknüpft sind, werden ebenfalls gelöscht. Möchten Sie diese Inhaltstypen wirklich löschen? Wenn Sie sich nicht sicher sind, antworten Sie mit "Nein".
Es benennt alle vorhandenen Daten um und migriert sie für mich in eine neue benannte Tabelle.
quelle
Leider habe ich Probleme (bei jedem Django 1.x) mit der Umbenennungsmigration festgestellt, bei denen alte Tabellennamen in der Datenbank verbleiben.
Django probiert nicht einmal etwas auf dem alten Tisch aus, sondern benennt einfach sein eigenes Modell um. Das gleiche Problem mit Fremdschlüsseln und Indizes im Allgemeinen - Änderungen dort werden von Django nicht richtig verfolgt.
Die einfachste Lösung (Problemumgehung):
Die eigentliche Lösung (eine einfache Möglichkeit, alle Indizes, Einschränkungen, Trigger, Namen usw. in 2 Commits zu wechseln, jedoch für kleinere Tabellen):
Commit A:
Bar
. (einschließlich aller Beziehungen im Schema)Bei der Migration vorbereiten
RunPython
, welche Daten von Foo nach Bar kopieren (einschließlichid
von Foo)Commit B: (keine Eile, mach es, wenn ein ganzes Team migriert wird)
Foo
weitere Bereinigung:
Fehler in Django:
quelle
Ich wollte nur den Kommentar von ceasaro bestätigen und hinzufügen. Django 2.0 scheint dies jetzt automatisch zu tun.
Ich bin auf Django 2.2.1, alles was ich tun musste, um das Modell umzubenennen und auszuführen
makemigrations
.Hier wird gefragt, ob ich die bestimmte Klasse von
A
in umbenannt habe. Ich habeB
Ja gewählt und migrate ausgeführt, und alles scheint zu funktionieren.Hinweis Ich habe den alten Modellnamen in keiner Datei im Projekt- / Migrationsordner umbenannt.
quelle
Ich musste ein paar Tabellen umbenennen. Django bemerkte jedoch nur eine Umbenennung des Modells. Dies geschah, weil Django über hinzugefügte und dann entfernte Modelle iteriert. Für jedes Paar wird geprüft, ob sie zur selben App gehören und identische Felder haben . Nur eine Tabelle hatte keine Fremdschlüssel für umbenennende Tabellen (Fremdschlüssel enthalten, wie Sie sich erinnern, den Namen der Modellklasse). Mit anderen Worten, nur eine Tabelle hatte keine Feldänderungen. Deshalb wurde es bemerkt.
Die Lösung besteht also darin, jeweils eine Tabelle umzubenennen
models.py
, möglicherweise den Namen der Modellklasse zu ändernviews.py
und eine Migration durchzuführen. Überprüfen Sie anschließend Ihren Code auf andere Referenzen (Modellklassennamen, verwandte (Abfrage-) Namen, Variablennamen). Führen Sie bei Bedarf eine Migration durch. Kombinieren Sie dann optional alle diese Migrationen zu einer (kopieren Sie auch die Importe).quelle
Ich würde @ceasaro Worte machen, meine zu seinem Kommentar zu dieser Antwort .
Neuere Versionen von Django können Änderungen erkennen und nachfragen, was getan wurde. Ich würde auch hinzufügen, dass Django die Reihenfolge der Ausführung einiger Migrationsbefehle mischen könnte.
Es wäre klug, kleine Änderungen zu übernehmen und ausführen
makemigrations
undmigrate
falls der Fehler der Datei bearbeitet werden kann Migration auftritt.Die Ausführungsreihenfolge einiger Zeilen kann geändert werden, um Fehler zu vermeiden.
quelle
migrations.SeparateDatabaseAndState
das helfen kann?Wenn Sie eine gute IDE wie PyCharm verwenden, können Sie mit der rechten Maustaste auf den Modellnamen klicken und einen Refactor ausführen -> umbenennen. Dies erspart Ihnen die Mühe, den gesamten Code durchzugehen, der auf das Modell verweist. Führen Sie dann Makemigrationen durch und migrieren Sie. Django 2+ bestätigt einfach die Namensänderung.
quelle
Ich habe Django von Version 10 auf Version 11 aktualisiert:
(
-U
für "Upgrade") und es löste das Problem.quelle