4 Stimmen

Südliche Datenmigration von einer übergeordneten Klasse zu einer Unterklasse beeinträchtigt die übergeordneten Daten

Ich habe eine Legacy-Django-Modell, das ein wenig zu spezifisch in seiner Umsetzung für meinen Geschmack ist. Ich möchte spezifischere Unterklassen dieses Modells erstellen, um verschiedene Szenarien zu behandeln, aber eine gemeinsame Basisklasse für einige gemeinsame Felder und Methoden beibehalten. Das Beispielmodell ist wie folgt:

class SomeOldClass(models.Model):
    sharedField1 = models.CharField('This is a shared field1', max_length=10)
    sharedField2 = models.CharField('This is a shared field2', max_length=10)
    specificField1 = models.CharField('This is a specific field1', max_length=10)

Letztlich versuche ich, eine Unterklasse von SomeOldClass zu erstellen, die sharedField1 und sharedField2 gemeinsam nutzt.

class SomeOldSubclass(SomeOldClass):
    specificField1_new = models.CharField('This is a specific field1', max_length=10)

Beachten Sie das _new, das an das specificField1 in SomeOldSubclass angehängt wurde, um Fehler beim Erstellen eines Feldes mit demselben Namen wie ein übergeordnetes Feld zu vermeiden.

Mein Plan ist es, drei Süd-Skripte zu haben:

  1. Schemamigration zur Erstellung des neuen app_someoldsubclass-Tabelle
  2. Daten Migrationsskript zum Kopieren von Werten aus app_someoldclass.specificField1 nach app_someoldsubclass.specificField1_new
  3. Schemamigration nach unten specificField1 aus app_someoldclass und Umbenennung von specificField1_new in specificField1 in app_someoldsubclass

Natürlich könnte ich diese Skripte in einem Migrationsskript zusammenfassen, aber ich bitte um Nachsicht.

Mit den oben definierten Klassen habe ich ein Skript zur Schemamigration erstellt: ./manage.py schemamigration app --auto

Dann habe ich ein Skript für die Datenmigration mit Leerzeichen erstellt: ./manage.py datamigration app copy_values

Ich habe das Skript für die Datenmigration geändert, um dies in meine Vorwärtsmethode aufzunehmen:

def forwards(self, orm):
    "Write your forwards methods here."
    for soc in orm.SomeOldClass.objects.all():
        sosc = orm.SomeOldSubclass.objects.get_or_create(someoldclass_ptr=soc, specificField_new=soc.specificField1)

Da SomeOldSubclass von SomeOldClass erbt, erstelle ich für jede Instanz von SomeOldClass eine neue SomeOldSubclass-Instanz und aktualisiere die Werte someoldclass_ptr und specificField1_new.

Beim Ausführen der Migrationen wird wie erwartet für jede Zeile in app_someoldclass eine neue Zeile in app_someoldsubclass erstellt, wobei der Wert von specificField1_new mit dem Wert in app_someoldclass.specificField1 übereinstimmt. Aber jetzt sind alle Felder in app_someoldclass komplett ausgelöscht. Wenn ich eine Instanz des SomeOldClass-Modells für eine vorhandene id, sharedField1 wäre None . Tatsächlich ist der einzige Wert, der noch gültig ist, die ID in app_someoldclass.

Die einzige Möglichkeit, die ursprünglichen Werte von app_someoldclass beizubehalten, besteht darin, meine Vorwärtsmethode wie folgt zu ändern:

def forwards(self, orm):
    "Write your forwards methods here."
    for soc in orm.SomeOldClass.objects.all():
        sosc = orm.SomeOldSubclass.objects.get_or_create(someoldclass_ptr=soc, specificField_new=soc.specificField1)
        soc.save()

(Anmerkung: Hinzufügung von soc.save() )

Ist dieses Verhalten zu erwarten? Ich würde davon ausgehen, dass, da ich meine Instanzen von SomeOldClass, wie sie durch das soc-Objekt dargestellt werden, nicht ändere, es nicht notwendig wäre, sie erneut zu speichern. Und selbst wenn ich es nicht speichern würde, würde ich sicher nicht erwarten, dass die Daten verloren gehen.

Ist das eine Sache des Südens? Eine Django-Sache? Eine Sache der Benutzerfehler?

0voto

Tomasz Wysocki Punkte 10546

Das Problem liegt in get_or_create. Es funktioniert anders, als Sie es erwarten.

Es gibt zwei Möglichkeiten, dieses Problem zu lösen:

  • nicht get_oder_create verwenden, oder
  • das Problem zu beheben

Um das Problem zu beheben, sollten Sie:

  • get_or_create-Dokumentation lesen
  • vielleicht lesen get_or_create Implementierung
  • sich die erzeugten SQL-Anweisungen ansehen

0voto

Mike Bryant Punkte 992

Das Problem liegt nicht im Süden, sondern in Ihrer Verwendung von Unterklassen

Wenn Sie eine Unterklasse speichern, werden alle Werte aus ihren Feldern in der Datenbank gesetzt. Ihr sosc-Objekt wurde mit allen übergeordneten abgeleiteten Feldern mit ihren Standardwerten erstellt.

Wenn Sie die Unterklasse speichern, überschreibt sie die übergeordnete Klasse. Dann setzt soc.save() die übergeordnete Klasse wieder auf ihre ursprünglichen Werte zurück.

参照 https://code.djangoproject.com/ticket/7623

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X