Wie kann ich Signale von Django-Migrationen senden?

9

Ich verwende Django 1.7-Migrationen und möchte insbesondere eine neu erstellte Datenbank mit Anfangsdaten füllen. Daher verwende ich hierfür eine Datenmigration. Es sieht so aus:

%Vor%

Gleichzeitig möchte ich eine Instanz des UserDetails -Modells für jeden neuen Benutzer haben:

%Vor%

Aber : Dieses Signal funktioniert nur außerhalb der Migration. Der Grund ist, dass apps.get_model("auth", "User") von django.contrib.auth.models.User so verschieden ist, dass kein Signal gesendet wird. Wenn ich es manuell versuche, so scheitert es:

%Vor%

Dies schlägt fehl, weil der Signalhandler dann versucht, ein neues UserDetails , das mit O2O zeigt, zu einem historischen User :

zu erstellen %Vor%

Bummer.

Okay, ich könnte den Signal-Handler direkt aufrufen. Aber ich musste die historische UserDetails -Klasse in einem Schlüsselwortargument (und anderen historischen Klassen, die es benötigt) übergeben. Außerdem ist die App mit der UserDetails nicht diejenige mit dieser Datenmigration, so dass dies eine hässliche Abhängigkeit wäre, die leicht brechen kann, z. wenn die App UserDetails aus INSTALLED_APPS entfernt wird.

Also, ist das einfach eine aktuelle Einschränkung, die ich mit hässlichem Code und einem FixMe-Kommentar angehen muss? Oder gibt es eine Möglichkeit, Signale aus Datenmigrationen zu senden?

    
Torsten Bronger 24.10.2014, 06:31
quelle

1 Antwort

3

Sie können dies nicht tun (und sollten dies auch nicht), da Ihre UserDetails beim Ausführen Ihrer Migration wirklich anders sein könnte als beim Erstellen dieser Migration. Aus diesem Grund verwenden Django (und Süden) "eingefrorene Modelle", die mit denen identisch sind, als Sie die Migration geschrieben haben.

"Leider", Sie müssen Ihren Signalcode in der Migration einfrieren, damit das Verhalten zum Zeitpunkt des Schreibens der Migration beibehalten wird. .

Ein einfaches Beispiel, um zu verstehen, warum es wichtig ist, in einer Migration keine realen Modelle (oder Signale usw.) zu verwenden:

Heute könnte ich das haben:

%Vor%

Dann habe ich eine Datenmigration ("populate_users"), die neue Benutzer erzeugt und die Ausführung von add_user_details darin erzwingt. Es ist in Ordnung: Es funktioniert heute .

Morgen fixiere ich meine typo_fild - & gt; typo_field innerhalb UserDetails und innerhalb add_user_details . Eine neue Schemamigration wird erstellt, um das Feld in der Datenbank umzubenennen.

Zu diesem Zeitpunkt wird meine Migration "populate_users" fehlschlagen , wenn ein neuer Benutzer erstellt wird, wird versucht, ein neues UserDetails mit einem Feld "typo_field" zu erstellen, das noch nicht erstellt wurde in der Datenbank vorhanden: Dieses Feld wird nur bei den nächsten Migrationen im DB umbenannt.

Also, wenn ich eine gute Migration behalten möchte, die jederzeit funktioniert, muss ich das Verhalten von add_user_details in die Migration kopieren. Dieses Einfrieren von add_user_details muss das eingefrorene Modell UserDetails via apps.get_model("myapp", "UserDetails") verwenden und ein neues UserDetails mit dem ebenfalls eingefrorenen typo_fild erstellen.

    
DylannCordel 27.10.2015 11:36
quelle