Chcę wyzwolić specjalną akcję w metodzie save () obiektu modelu Django, kiedy zapisuję nowy rekord (nie aktualizuję istniejącego rekordu).
Czy sprawdzenie (self.id! = None) jest konieczne i wystarczające, aby zagwarantować, że zapis własny jest nowy i nie jest aktualizowany? Czy są jakieś szczególne przypadki, które może przeoczyć?
django
django-models
MikeN
źródło
źródło
UUIDField pk
Odpowiedzi:
Zaktualizowano: Z wyjaśnieniem, że
self._state
nie jest to zmienna prywatnej instancji, ale nazwana w ten sposób, aby uniknąć konfliktów, sprawdzanieself._state.adding
jest teraz preferowanym sposobem sprawdzania.zwraca True w nowym obiekcie Model, chyba że obiekt ma
UUIDField
jako swójprimary_key
.Problem narożny, o który możesz się martwić, dotyczy tego, czy istnieją ograniczenia unikalności w polach innych niż id (np. Drugorzędne unikalne indeksy w innych polach). W takim przypadku nadal możesz mieć w ręku nowy rekord, ale nie możesz go zapisać.
źródło
is not
raczej używać niż!=
podczas sprawdzania tożsamości zNone
obiektemmodels.OneToOneField(OtherModel, primary_key=True)
. Myślę, że musisz użyćself.pk
UUIDField
jako klucza podstawowego,self.pk
nigdy nie jestNone
.Alternatywnym sposobem sprawdzenia
self.pk
jest sprawdzenieself._state
modeluself._state.adding is True
tworzenieself._state.adding is False
aktualizacjaMam to z tej strony
źródło
self._state.adding
działa, ale uczciwe ostrzeżenie, że wydaje się zawsze równe,False
jeśli sprawdzasz to po wywołaniusuper(TheModel, self).save(*args, **kwargs)
: github.com/django/django/blob/stable/1.10.x/django/db/models/ …_state
nie jest prywatne; na przykład_meta
jest poprzedzony podkreśleniem, aby uniknąć pomyłki z nazwami pól. (Zwróć uwagę, jak jest używany wis_new = self._state.adding
, wtedysuper(MyModel, self).save(*args, **kwargs)
i potemif is_new: my_custom_logic()
Sprawdzanie
self.id
zakłada, żeid
jest to klucz podstawowy dla modelu. Bardziej ogólnym sposobem byłoby użycie skrótu pk .is_new = self.pk is None
źródło
super(...).save()
.Sprawdzenie nie
self.pk == None
jest wystarczające, aby określić, czy obiekt ma zostać wstawiony lub zaktualizowany w bazie danych.Django O / RM zawiera szczególnie paskudny hack, który polega po prostu na sprawdzeniu, czy coś jest na pozycji PK, a jeśli tak, wykonaj AKTUALIZACJĘ, w przeciwnym razie wykonaj INSERT (zostanie zoptymalizowany do INSERT, jeśli PK ma wartość None).
Powodem, dla którego musi to zrobić, jest to, że możesz ustawić PK podczas tworzenia obiektu. Chociaż nie jest to powszechne, gdy masz kolumnę sekwencji dla klucza podstawowego, nie dotyczy to innych typów pól klucza podstawowego.
Jeśli naprawdę chcesz wiedzieć, musisz zrobić to, co robi O / RM i zajrzeć do bazy danych.
Oczywiście masz konkretny przypadek w kodzie i za to, że jest całkiem prawdopodobne, że
self.pk == None
powie Ci wszystko, co musisz wiedzieć, ale to nie ogólne rozwiązanie.źródło
UUIDField
klucza podstawowego jako klucza podstawowego: klucz nie jest zapełniany na poziomie bazy danych, więcself.pk
jest zawszeTrue
.Możesz po prostu połączyć się z sygnałem post_save, który wysyła "utworzone" kwargi, jeśli prawda, to twój obiekt został wstawiony.
http://docs.djangoproject.com/en/stable/ref/signals/#post-save
źródło
ATOMIC_REQUESTS
, więc nie jestem pewien co do wartości domyślnej.Sprawdź
self.id
iforce_insert
flagę.Jest to przydatne, ponieważ nowo utworzony obiekt (jaźń) ma swoją
pk
wartośćźródło
Jestem bardzo spóźniony na tę rozmowę, ale napotkałem problem z wypełnianiem pliku self.pk, gdy ma skojarzoną z nim wartość domyślną.
Sposób obejścia tego polega na dodaniu pola date_created do modelu
date_created = models.DateTimeField(auto_now_add=True)
Stąd możesz iść
created = self.date_created is None
źródło
Aby uzyskać rozwiązanie, które działa również wtedy, gdy masz
UUIDField
klucz podstawowy (który, jak zauważyli inni, nie jest,None
jeśli po prostu nadpisujeszsave
), możesz podłączyć się do sygnału post_save Django . Dodaj to do swojego models.py :To wywołanie zwrotne zablokuje
save
metodę, więc możesz wykonywać takie czynności, jak powiadomienia wyzwalające lub aktualizować model dalej, zanim odpowiedź zostanie wysłana z powrotem przez sieć, niezależnie od tego, czy używasz formularzy, czy struktury Django REST do wywołań AJAX. Oczywiście używaj odpowiedzialnie i przeładowuj ciężkie zadania do kolejki zadań, zamiast czekać, aż użytkownicy będą czekać :)źródło
raczej użyj pk zamiast id :
źródło
Jest to powszechny sposób.
identyfikator zostanie nadany podczas pierwszego zapisania do bazy danych
źródło
Czy to zadziała we wszystkich powyższych scenariuszach?
źródło
źródło
Aby wiedzieć, czy aktualizujesz, czy wstawiasz obiekt (dane), użyj
self.instance.fieldname
w swoim formularzu. Zdefiniuj czystą funkcję w swoim formularzu i sprawdź, czy bieżąca wartość jest taka sama jak poprzednia, jeśli nie, to ją aktualizujesz.self.instance
iself.instance.fieldname
porównaj z nową wartościąźródło