Frage

Ich plane, mehrere Modelle in einem bestehenden 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 dafür mehrere Migrationen erforderlich sein werden, aber ich bin mir über die genaue Vorgehensweise nicht sicher.

Nehmen wir an, 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 umbenennen Foo Modell, weil der Name keinen Sinn ergibt und Verwirrung im Code verursacht, und Bar würde zu einem viel klareren Namen führen.

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 das AnotherModel Feldname für foo ändert sich nicht, aber die Beziehung wird auf aktualisiert Bar Modell.Meine Argumentation ist, dass ich nicht zu viel auf einmal ändern sollte und dass ich diesen Feldnamen in ändern würde bar Ich würde riskieren, die Daten in dieser Spalte zu verlieren.

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 hinzuzufügen RenameModel Operation zur Operationsliste hinzufü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 class in der in Schritt 6 erstellten Migrationsdatei, um die hinzuzufügen RenameField Operation(en) für alle zugehörigen Feldnamen zur Operationsliste:

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 von der Aktualisierung des restlichen Codes (Ansichten, Formulare usw.), um die neuen Variablennamen widerzuspiegeln, würde die neue Migrationsfunktion im Grunde so funktionieren?

Außerdem scheinen das viele Schritte zu sein.Können die Migrationsvorgänge irgendwie komprimiert werden?

Danke!

War es hilfreich?

Lösung

Als ich das ausprobiert habe, scheint es, dass Sie die Schritte 3 bis 7 zusammenfassen können:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'), 
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar'),
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

Möglicherweise erhalten Sie Fehlermeldungen, wenn Sie die Namen dort, wo sie importiert werden, nicht aktualisieren, z. B.admin.py und sogar ältere Migrationsdateien (!).

Aktualisieren:Als Caesar Wie bereits erwähnt, sind neuere Versionen von Django normalerweise in der Lage, die Umbenennung eines Modells zu erkennen und zu fragen.Also versuche manage.py makemigrations zuerst und überprüfen Sie dann die Migrationsdatei.

Andere Tipps

Zuerst dachte ich, dass die Methode von Fiver für mich funktioniert, weil die Migration bis Schritt 4 gut funktioniert hat.Die impliziten Änderungen von „ForeignKeyField(Foo)“ in „ForeignKeyField(Bar)“ waren jedoch bei keiner Migration im Zusammenhang.Aus diesem Grund schlug die Migration fehl, 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 ist es mir gelungen, meine Modelle und Beziehungsfelder mithilfe der folgenden Schritte umzubenennen:

Ich habe die Methode von angepasst Das und insbesondere der Trick von Otranzer.

Nehmen wir also wie Fiver an, wir sind dabei meine App:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

Und in meineotherapp:

class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

Schritt 1:

Verwandeln Sie jedes OneToOneField(Foo) oder ForeignKeyField(Foo) in IntegerField().(Dadurch bleibt die ID des zugehörigen Foo-Objekts als Wert des Ganzzahlfelds erhalten.)

class AnotherModel(models.Model):
    foo = models.IntegerField()
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.IntegerField()
    is_ridonkulous = models.BooleanField()

Dann

python manage.py makemigrations

python manage.py migrate

Schritt 2:(Wie Schritt 2-4 von Fiver)

Ändern Sie den Modellnamen

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

Erstellen Sie eine leere Migration:

python manage.py makemigrations --empty myapp

Dann bearbeiten Sie es wie folgt:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

Letztlich

python manage.py migrate

Schritt 3:

Transformieren Sie Ihr IntegerField() wieder in das vorherige ForeignKeyField oder OneToOneField, jedoch mit dem neuen Balkenmodell.(Das vorherige Ganzzahlfeld speicherte die ID, also versteht Django das und stellt die Verbindung wieder her, was cool ist.)

class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_ridonkulous = models.BooleanField()

Dann mach:

python manage.py makemigrations 

Ganz wichtig ist, dass Sie in diesem Schritt alle neuen Migrationen ändern und die Abhängigkeit von den RenameModel Foo-> Bar-Migrationen hinzufügen müssen.Wenn sich also sowohl AnotherModel als auch YetAnotherModel in myotherapp befinden, muss die erstellte Migration in myotherapp so aussehen:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'),
        ('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'),
    ]

    operations = [
        migrations.AlterField(
            model_name='anothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar'),
        ),
        migrations.AlterField(
            model_name='yetanothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar')
        ),
    ]

Dann

python manage.py migrate

Schritt 4:

Eventuell können Sie Ihre Felder umbenennen

class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_ridonkulous = models.BooleanField()

und führen Sie dann eine automatische Umbenennung durch

python manage.py makemigrations

(Django sollte Sie fragen, ob Sie den Modellnamen tatsächlich umbenannt haben, sagen Sie „Ja“)

python manage.py migrate

Und das ist es!

Dies funktioniert auf Django1.8

Ich musste das Gleiche tun.Ich habe das Modell auf einmal geändert (d. h. Schritt 1 und Schritt 5 zusammen).Dann wurde eine Schemamigration erstellt, diese jedoch wie folgt bearbeitet:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('Foo','Bar')

    def backwards(self, orm):
        db.rename_table('Bar','Foo')

Das hat perfekt funktioniert.Alle meine vorhandenen Daten wurden angezeigt, alle anderen Tabellen, auf die verwiesen wurde, sind in Ordnung.

von hier: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/

Für Django 1.10 ist es mir gelungen, zwei Modellklassennamen (einschließlich eines ForeignKey und mit Daten) zu ändern, indem ich einfach „Makemigrations“ und dann „Migrate“ für die App ausgeführt habe.Für den Makemigrations-Schritt musste ich bestätigen, dass ich die Tabellennamen ändern wollte.Migrate hat die Namen der Tabellen problemlos geändert.

Dann änderte ich den Namen des ForeignKey-Felds entsprechend und wurde erneut von Makemigrations gebeten, zu bestätigen, dass ich den Namen ändern wollte.Migrieren Sie dann die Änderung.

Also habe ich dies in zwei Schritten ohne besondere Dateibearbeitung durchgeführt.Zuerst bekam ich Fehlermeldungen, weil ich vergessen hatte, die Datei admin.py zu ändern, wie von @wasibigeek erwähnt.

Ich war auch mit dem von v.thorey beschriebenen Problem konfrontiert und stellte fest, dass sein Ansatz sehr nützlich ist, aber auf weniger Schritte reduziert werden kann, nämlich die Schritte 5 bis 8, wie Fiver es beschrieben hat, ohne die Schritte 1 bis 4, außer dass Schritt 7 als mein geändert werden muss unten Schritt 3.Die allgemeinen Schritte sind wie folgt:

Schritt 1: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 2:Erstellen Sie eine leere Migration

python manage.py makemigrations --empty myapp

Schritt 3:Bearbeiten Sie die Migrationsklasse in der in Schritt 2 erstellten Migrationsdatei

class Migration(migrations.Migration):

dependencies = [
    ('myapp', '0001_initial'), 
]

operations = [
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.RenameModel('Foo', 'Bar'),
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.RenameField('AnotherModel', 'foo', 'bar'),
    migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]

Schritt 4:Wenden Sie die Migration an

python manage.py migrate

Erledigt

P.S.Ich habe diesen Ansatz auf Django 1.9 ausprobiert

Ich verwende Django Version 1.9.4

Ich habe die folgenden Schritte befolgt:-

Ich habe gerade den Model Oldname in NewName Run umbenannt python manage.py makemigrations.Es wird Sie danach fragenDid you rename the appname.oldName model to NewName? [y/N] Wählen Sie Y

Laufen python manage.py migrate und es wird dich darum bitten

Die folgenden Inhaltstypen sind veraltet und müssen gelöscht werden:

appname | oldName
appname | NewName

Alle Objekte, die sich mit diesen Inhaltstypen von einem Fremdschlüssel beziehen, werden ebenfalls gelöscht.Sind Sie sicher, dass Sie diese Inhaltstypen löschen möchten?Wenn Sie sich nicht sicher sind, antworten Sie mit „Nein“.

Type 'yes' to continue, or 'no' to cancel: Select No

Für mich werden alle vorhandenen Daten umbenannt und in eine neue benannte Tabelle migriert.

Leider habe ich Probleme (jeweils Django 1.x) bei der Umbenennungsmigration festgestellt, die dazu führen, dass 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 ordnungsgemäß verfolgt.

Die einfachste Lösung (Workaround):

class Foo(models.Model):
     name = models.CharField(unique=True, max_length=32)
     ...
Bar = Foo  # and use Bar only

Die eigentliche Lösung (eine einfache Möglichkeit, alle Indizes, Einschränkungen, Auslöser, Namen usw. in 2 Commits zu wechseln, sondern für eher kleiner Tabellen):

Commit A:

  1. Erstellen Sie die Dasselbe Modell wie das alte
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
    ...

class Bar(model.Model):
    ...
  1. Ändern Sie den Code, um mit dem neuen Modell zu arbeiten Bar nur.(einschließlich aller Beziehungen im Schema)

Bereiten Sie sich auf die Migration vor RunPython, die Daten von Foo in Bar kopieren (einschließlich id von Foo)

  1. optionale Optimierung (bei Bedarf für größere Tabellen)

Commit B: (keine Eile, tun Sie es, wenn ein ganzes Team migriert wird)

  1. sicherer Abwurf des alten Modells Foo

weitere Aufräumarbeiten:

  • Squash auf Migrationen

Fehler in Django:

Ich musste ein paar Tabellen umbenennen.Aber nur eine Modellumbenennung wurde von Django bemerkt.Das geschah, weil Django erst hinzugefügte und dann entfernte Modelle iterierte.Für jedes Paar wird geprüft, ob es sich um dieselbe App handelt identische Felder.Nur eine Tabelle hatte keine Fremdschlüssel für umzubenennende Tabellen (Fremdschlüssel enthalten, wie Sie sich erinnern, den Namen der Modellklasse).Mit anderen Worten: Nur eine Tabelle hatte keine Feldänderungen.Deshalb ist es aufgefallen.

Die Lösung besteht also darin, jeweils eine Tabelle umzubenennen und den Namen der Modellklasse in zu ändern models.py, möglicherweise views.py, und eine Migration durchführen.Überprüfen Sie anschließend Ihren Code auf andere Referenzen (Modellklassennamen, zugehörige (Abfrage-)Namen, Variablennamen).Führen Sie bei Bedarf eine Migration durch.Kombinieren Sie dann optional alle diese Migrationen in einer (achten Sie darauf, auch Importe zu kopieren).

Ich würde die Worte von @ceasaro zu meinem Kommentar zu diesem Thema machen Antwort.

Neuere Versionen von Django können Änderungen erkennen und nachfragen, was getan wurde.Ich möchte auch hinzufügen, dass Django die Ausführungsreihenfolge einiger Migrationsbefehle verwechseln könnte.

Es wäre ratsam, kleine Änderungen vorzunehmen und auszuführen makemigrations Und migrate und wenn der Fehler auftritt, kann die Migrationsdatei bearbeitet werden.

Die Ausführungsreihenfolge einiger Zeilen kann geändert werden, um Fehler zu vermeiden.

Ich wollte den Kommentar von Ceasaro nur bestätigen und ergänzen.Django 2.0 scheint dies jetzt automatisch zu tun.

Ich verwende Jango 2.2.1 und musste lediglich das Modell umbenennen und makemigrations ausführen.

Hier wird gefragt, ob ich die spezifische Klasse von A in B umbenannt habe, ich habe „Ja“ gewählt und „migrate“ ausgeführt, und alles scheint zu funktionieren.

Hinweis: Ich habe den alten Modellnamen in keiner der Dateien im Ordner „project/migrations“ umbenannt.

Wenn Sie eine gute IDE wie PyCharm verwenden, können Sie mit der rechten Maustaste auf den Modellnamen klicken und einen Refactor -> Umbenennen durchführen.Dies erspart Ihnen die Mühe, Ihren gesamten Code durchzugehen, der auf das Modell verweist.Führen Sie dann makemigrations aus und migrieren Sie.Django 2+ bestätigt lediglich die Namensänderung.

Ich habe Django von Version 10 auf Version 11 aktualisiert:

sudo pip install -U Django

(-U für „Upgrade“) und es hat das Problem gelöst.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top