Ich möchte eine spezielle Aktion in der save () -Methode eines Django-Modellobjekts auslösen, wenn ich einen neuen Datensatz speichere (ohne einen vorhandenen Datensatz zu aktualisieren).
Ist die Überprüfung auf (self.id! = None) notwendig und ausreichend, um sicherzustellen, dass der Self Record neu ist und nicht aktualisiert wird? Gibt es Sonderfälle, die dies übersehen könnte?
django
django-models
MikeN
quelle
quelle
UUIDField pk
Antworten:
Aktualisiert: Mit der Klarstellung, dass
self._state
es sich nicht um eine private Instanzvariable handelt, sondern so benannt wurde, um Konflikte zu vermeiden,self._state.adding
ist die Überprüfung jetzt die bevorzugte Methode zur Überprüfung.Gibt True innerhalb eines neuen Modellobjekts zurück, es sei denn, das Objekt hat ein
UUIDField
as als seinprimary_key
.Der Eckfall, über den Sie sich möglicherweise Sorgen machen müssen, ist, ob es Eindeutigkeitsbeschränkungen für andere Felder als die ID gibt (z. B. sekundäre eindeutige Indizes für andere Felder). In diesem Fall haben Sie möglicherweise noch einen neuen Datensatz in der Hand, können ihn jedoch nicht speichern.
quelle
is not
eher verwenden als!=
bei der Überprüfung der Identität mit demNone
Objektmodels.OneToOneField(OtherModel, primary_key=True)
. Ich denke, Sie müssen verwendenself.pk
UUIDField
als Primärschlüssel verwenden,self.pk
ist dies niemals der FallNone
.Alternativ zur Überprüfung können
self.pk
wirself._state
das Modell überprüfenself._state.adding is True
Erstellenself._state.adding is False
AktualisierungIch habe es von dieser Seite bekommen
quelle
self._state.adding
funktioniert, aber eine faire Warnung, dass es immer gleich zu sein scheint,False
wenn Sie es nach dem Anruf überprüfensuper(TheModel, self).save(*args, **kwargs)
: github.com/django/django/blob/stable/1.10.x/django/db/models/ …_state
ist nicht privat; wie_meta
, ist es mit einem Unterstrich zu vermeiden Verwechslungen mit Feldnamen vorangestellt. (Beachten Sie, wie es in der verknüpften Dokumentation verwendet wird.)is_new = self._state.adding
dannsuper(MyModel, self).save(*args, **kwargs)
und dannif is_new: my_custom_logic()
Bei der Überprüfung wird
self.id
davon ausgegangen , dass diesid
der Primärschlüssel für das Modell ist. Ein allgemeinerer Weg wäre die Verwendung der pk-Verknüpfung .is_new = self.pk is None
quelle
super(...).save()
.Die Prüfung auf
self.pk == None
ist nicht ausreichend , um zu bestimmen , ob das Objekt wird in der Datenbank eingefügt oder aktualisiert werden.Das Django O / RM verfügt über einen besonders bösen Hack, bei dem im Grunde genommen überprüft wird, ob sich etwas an der PK-Position befindet, und wenn ja, ein UPDATE durchgeführt wird, andernfalls ein INSERT (dies wird zu einem INSERT optimiert, wenn die PK None ist).
Der Grund dafür ist, dass Sie die PK festlegen dürfen, wenn ein Objekt erstellt wird. Obwohl dies nicht üblich ist, wenn Sie eine Sequenzspalte für den Primärschlüssel haben, gilt dies nicht für andere Arten von Primärschlüsselfeldern.
Wenn Sie wirklich wissen wollen, müssen Sie das tun, was der O / RM tut, und in der Datenbank suchen.
Natürlich haben Sie einen bestimmten Fall in Ihrem Code und dafür ist es sehr wahrscheinlich,
self.pk == None
dass er Ihnen alles sagt, was Sie wissen müssen, aber es ist keine allgemeine Lösung.quelle
UUIDField
als Primärschlüssel: Der Schlüssel wird nicht auf DB-Ebene ausgefüllt, sondernself.pk
immerTrue
.Sie können sich einfach mit dem Signal post_save verbinden, das ein "erstelltes" kwargs sendet. Wenn true, wurde Ihr Objekt eingefügt.
http://docs.djangoproject.com/de/stable/ref/signals/#post-save
quelle
ATOMIC_REQUESTS
, daher bin ich mir über die Standardeinstellung nicht sicher.Überprüfen Sie für
self.id
und dieforce_insert
Flagge.Dies ist praktisch, da Ihr neu erstelltes Objekt (Selbst) seinen
pk
Wert hatquelle
Ich bin sehr spät zu dieser Konversation gekommen, aber ich bin auf ein Problem mit der Datei self.pk gestoßen, die ausgefüllt wird, wenn ihr ein Standardwert zugeordnet ist.
Um dies zu umgehen, füge ich dem Modell ein Feld date_created hinzu
date_created = models.DateTimeField(auto_now_add=True)
Von hier aus können Sie gehen
created = self.date_created is None
quelle
Für eine Lösung, die auch dann funktioniert, wenn Sie
UUIDField
einen Primärschlüssel haben (was, wie andere angemerkt haben, nicht der Fall ist,None
wenn Sie nur überschreibensave
), können Sie das post_save- Signal von Django anschließen . Fügen Sie dies Ihrer models.py hinzu :Dieser Rückruf blockiert die
save
Methode, sodass Sie beispielsweise Benachrichtigungen auslösen oder das Modell weiter aktualisieren können, bevor Ihre Antwort über das Netzwerk zurückgesendet wird, unabhängig davon, ob Sie Formulare oder das Django REST-Framework für AJAX-Aufrufe verwenden. Verwenden Sie verantwortungsbewusst und verlagern Sie schwere Aufgaben in eine Jobwarteschlange, anstatt Ihre Benutzer warten zu lassen :)quelle
Verwenden Sie lieber pk anstelle von id :
quelle
Dies ist der übliche Weg.
Die ID wird beim ersten Speichern in der Datenbank angegeben
quelle
Würde dies für alle oben genannten Szenarien funktionieren?
quelle
quelle
Verwenden Sie
self.instance.fieldname
in Ihrem Formular , um festzustellen, ob Sie das Objekt (Daten) aktualisieren oder einfügen . Definieren Sie eine Bereinigungsfunktion in Ihrem Formular und prüfen Sie, ob der aktuelle Werteintrag mit dem vorherigen übereinstimmt. Wenn nicht, aktualisieren Sie ihn.self.instance
undself.instance.fieldname
mit dem neuen Wert vergleichenquelle