Ich habe ein Modell wie dieses:
class FooBar(models.Model):
createtime = models.DateTimeField(auto_now_add=True)
lastupdatetime = models.DateTimeField(auto_now=True)
Ich möchte die beiden Datumsfelder für einige Modellinstanzen (die beim Migrieren von Daten verwendet werden) überschreiben. Die aktuelle Lösung sieht folgendermaßen aus:
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
Gibt es eine bessere Lösung?
auto_now(_add)
Antworten:
Ich habe diese Situation kürzlich beim Testen meiner Anwendung erlebt. Ich musste einen abgelaufenen Zeitstempel "erzwingen". In meinem Fall habe ich den Trick mit einem Queryset-Update gemacht. So was:
quelle
update()
Verhalten genau das ist, was wir brauchen.Sie können auto_now / auto_now_add nicht auf eine andere Weise deaktivieren, als Sie es bereits getan haben. Wenn Sie die Flexibilität benötigen, um diese Werte zu ändern, ist
auto_now
/auto_now_add
nicht die beste Wahl. Es ist oft flexibler, das zu verwendendefault
und / oder zu überschreibensave()
die Manipulationsmethode unmittelbar vor dem Speichern des Objekts .Mit
default
und eine überschriebenesave()
Methode, ein Weg , um Ihr Problem zu lösen wäre Ihr Modell wie folgt zu definieren:Verwenden Sie in Ihrem Code, in dem Sie die automatische Änderung der letzten Aktualisierungszeit überspringen möchten, einfach
Wenn Ihr Objekt in der Administrationsoberfläche oder an anderen Stellen gespeichert wird, wird save () ohne das Argument skip_lastupdatetime aufgerufen und verhält sich wie zuvor mit
auto_now
.quelle
auto_now_add
Verwenden Siedefault
stattdessen nicht verwenden .datetime.datetime.now
eine naive Datums- / Uhrzeitangabe zurückgegeben wird. Um eine zeitzonenbezogene Datums-from django.utils import timezone
und Uhrzeitangabe zu verwenden, verwendenmodels.DateTimeField(default=timezone.now)
Sie docs.djangoproject.com/de/1.9/topics/i18n/timezones/…createtime
Feld ändern möchten, müssen Sie es nicht überschreibensave()
. Es reicht aus,auto_now_add=True
durch das Äquivalent zu ersetzendefault=timezone.now, editable=False, blank=True
(laut Dokumentation ). Die beiden letztgenannten Optionen stellen ein ähnliches Verhalten im Administrator sicher.Ich habe den Vorschlag des Fragestellers verwendet und einige Funktionen erstellt. Hier ist der Anwendungsfall:
Hier ist die Implementierung:
Ähnliche Funktionen können erstellt werden, um sie wieder einzuschalten.
quelle
Clazz._meta.get_field_by_name(field_name)[0]
.Sie können auch den
update_fields
Parameter von verwendensave()
und Ihreauto_now
Felder übergeben. Hier ist ein Beispiel:Hier ist die Erklärung aus der Dokumentation von Django: https://docs.djangoproject.com/de/stable/ref/models/instances/#specifying-which-fields-to-save
quelle
auto_now
und zu speichernauto_now_add
).Ich habe mich für die Wiederverwendbarkeit an den Kontextmanager gewandt.
Verwenden Sie wie folgt:
Boom.
quelle
Für diejenigen, die dies beim Schreiben von Tests betrachten, gibt es eine Python-Bibliothek namens freezegun , mit der Sie die Zeit vortäuschen können. Wenn der
auto_now_add
Code ausgeführt wird, erhält er die Zeit, die Sie tatsächlich möchten. So:Es kann auch als Dekorateur verwendet werden - grundlegende Dokumente finden Sie unter dem obigen Link.
quelle
Sie können
auto_now_add
ohne speziellen Code überschreiben .Ich bin auf diese Frage gestoßen, als ich versucht habe, ein Objekt mit einem bestimmten Datum zu erstellen:
wo
publication_date = models.DateField(auto_now_add=True)
.Das habe ich also getan:
Dies wurde erfolgreich überschrieben
auto_now_add
.Als langfristigere Lösung ist die überschreibende
save
Methode der richtige Weg: https://code.djangoproject.com/ticket/16583quelle
Ich musste auto_now für ein DateTime-Feld während einer Migration deaktivieren und konnte dies tun.
quelle
Ich bin zu spät zur Party, aber ähnlich wie bei einigen anderen Antworten ist dies eine Lösung, die ich während einer Datenbankmigration verwendet habe. Der Unterschied zu den anderen Antworten besteht darin, dass dadurch alle auto_now-Felder für das Modell deaktiviert werden, unter der Annahme, dass es wirklich keinen Grund gibt, mehr als ein solches Feld zu haben.
Um es dann zu verwenden, können Sie einfach Folgendes tun:
Und es wird alle Ihre
auto_now
undauto_now_add
Felder für alle Modellklassen, die Sie übergeben , durchlaufen und zerstören .quelle
Eine etwas sauberere Version des Kontextmanagers von https://stackoverflow.com/a/35943149/1731460
Sie können es sogar mit Fabriken (Fabrikjunge) verwenden
quelle
Kopie von Django - Models.DateTimeField - Dynamisch ändernder auto_now_add-Wert
Nun, ich habe diesen Nachmittag damit verbracht herauszufinden und das erste Problem ist, wie man ein Modellobjekt abruft und wo im Code. Ich bin in restframework in serializer.py, zum Beispiel in
__init__
serializer konnte es das Modell noch nicht haben. Jetzt können Sie in to_internal_value die Modellklasse abrufen, nachdem Sie das Feld abgerufen und die Feldeigenschaften wie in diesem Beispiel geändert haben:quelle
Ich brauchte eine Lösung, die funktioniert
update_or_create
. Ich bin zu dieser Lösung gekommen, die auf @ andreaspelme-Code basiert.Die einzige Änderung besteht darin, dass Sie das Überspringen festlegen können, indem Sie das geänderte Feld
skip
nicht nur auf das tatsächliche Übergeben von kwarg setzenskip_modified_update
, an die save () -Methode übergeben.Nur
yourmodelobject.modified='skip'
und Update wird übersprungen!quelle