Mam taki model:
class FooBar(models.Model):
createtime = models.DateTimeField(auto_now_add=True)
lastupdatetime = models.DateTimeField(auto_now=True)
Chcę nadpisać dwa pola daty dla niektórych wystąpień modelu (używane podczas migracji danych). Obecne rozwiązanie wygląda następująco:
for field in new_entry._meta.local_fields:
if field.name == "lastupdatetime":
field.auto_now = False
elif field.name == "createtime":
field.auto_now_add = False
new_entry.createtime = date
new_entry.lastupdatetime = date
new_entry.save()
for field in new_entry._meta.local_fields:
if field.name == "lastupdatetime":
field.auto_now = True
elif field.name == "createtime":
field.auto_now_add = True
Czy jest lepsze rozwiązanie?
auto_now(_add)
Odpowiedzi:
Niedawno spotkałem się z taką sytuacją podczas testowania mojej aplikacji. Musiałem „wymusić” wygasłą sygnaturę czasową. W moim przypadku załatwiłem sprawę, używając aktualizacji zestawu zapytań. Lubię to:
źródło
update()
zachowanie jest dokładnie tym, czego potrzebujemy.Naprawdę nie możesz wyłączyć auto_now / auto_now_add w inny sposób niż już to robisz. Jeśli potrzebujesz elastyczności, aby zmienić te wartości,
auto_now
/auto_now_add
nie jest najlepszym wyborem. Często bardziej elastyczne jest użyciedefault
i / lub nadpisaniesave()
metody wykonywania manipulacji tuż przed zapisaniem obiektu.Używając
default
isave()
metody zastępowanej , jednym ze sposobów rozwiązania problemu byłoby zdefiniowanie modelu w następujący sposób:W swoim kodzie, w którym chcesz pominąć automatyczną zmianę lastupdatetime, po prostu użyj
Jeśli twój obiekt jest zapisany w interfejsie administratora lub w innym miejscu, metoda save () zostanie wywołana bez argumentu skip_lastupdatetime i będzie zachowywać się tak samo, jak wcześniej
auto_now
.źródło
auto_now_add
używajdefault
zamiast tego.datetime.datetime.now
zwraca naiwną datę i godzinę. Aby użyć datyfrom django.utils import timezone
i godziny uwzględniającej strefę czasową, użyj imodels.DateTimeField(default=timezone.now)
zobacz docs.djangoproject.com/en/1.9/topics/i18n/timezones/ ...createtime
pola, nie musisz nadpisywaćsave()
. Wystarczy zastąpićauto_now_add=True
go odpowiednikiemdefault=timezone.now, editable=False, blank=True
(wg dok .). Dwie ostatnie opcje zapewniają podobne zachowanie w panelu administracyjnym.Skorzystałem z sugestii pytającego i stworzyłem kilka funkcji. Oto przypadek użycia:
Oto implementacja:
Można utworzyć podobne funkcje, aby je ponownie włączyć.
źródło
Clazz._meta.get_field_by_name(field_name)[0]
.Możesz również użyć
update_fields
parametrusave()
i przekazać swojeauto_now
pola. Oto przykład:Oto wyjaśnienie z dokumentacji Django: https://docs.djangoproject.com/en/stable/ref/models/instances/#specifying-which-fields-to-save
źródło
auto_now
iauto_now_add
).Poszedłem na ścieżkę menedżera kontekstu w celu ponownego wykorzystania.
Użyj w ten sposób:
Bum.
źródło
Dla tych, którzy patrzą na to podczas pisania testów, dostępna jest biblioteka Pythona o nazwie frozenegun, która pozwala sfałszować czas - więc kiedy
auto_now_add
kod działa, otrzymuje czas, którego faktycznie chcesz. Więc:Może być również używany jako dekorator - zobacz powyższy link do podstawowych dokumentów.
źródło
Możesz nadpisać
auto_now_add
bez specjalnego kodu.Na to pytanie natrafiłem, gdy próbowałem stworzyć obiekt z określoną datą:
gdzie
publication_date = models.DateField(auto_now_add=True)
.Oto co zrobiłem:
To zostało pomyślnie zastąpione
auto_now_add
.Bardziej długoterminowym rozwiązaniem
save
jest metoda zastępowania : https://code.djangoproject.com/ticket/16583źródło
Musiałem wyłączyć auto_now dla pola DateTime podczas migracji i mogłem to zrobić.
źródło
Spóźniłem się na imprezę, ale podobnie jak kilka innych odpowiedzi, jest to rozwiązanie, z którego korzystałem podczas migracji bazy danych. Różnica w stosunku do innych odpowiedzi polega na tym, że powoduje to wyłączenie wszystkich pól auto_now dla modelu przy założeniu, że nie ma powodu, aby mieć więcej niż jedną taką zmienną.
Następnie, aby go użyć, możesz po prostu zrobić:
I przejdzie przez wszystkie twoje pola
auto_now
iauto_now_add
wszystkie pola dla wszystkich klas modeli, w których zdasz.źródło
Nieco bardziej przejrzysta wersja menedżera kontekstu z https://stackoverflow.com/a/35943149/1731460
Możesz go używać nawet z fabrykami (fabrykant)
źródło
kopia Django - Models.DateTimeField - Dynamiczna zmiana wartości auto_now_add
Cóż, spędziłem dzisiejsze popołudnie, aby dowiedzieć się, a pierwszy problem dotyczy tego, jak pobrać obiekt modelu i gdzie w kodzie. Jestem w restframework w serializer.py, na przykład w
__init__
serializatorze nie mógł jeszcze mieć Modelu. Teraz w to_internal_value możesz pobrać klasę modelu, po pobraniu Field i zmodyfikowaniu właściwości pola jak w tym przykładzie:źródło
Potrzebowałem rozwiązania, które będzie działać
update_or_create
, doszedłem do tego rozwiązania opartego na kodzie @andreaspelme.Jedyną zmianą jest to, że możesz ustawić pomijanie, ustawiając zmodyfikowane pole na
skip
nie tylko przez faktyczne przekazanie kwargskip_modified_update
do metody save ().Tylko
yourmodelobject.modified='skip'
i aktualizacja zostanie pominięta!źródło