python model - Django auto_now und auto_now_add




fields tutorial (11)

Ist das ein Grund zur Besorgnis?

Nein, Django fügt es automatisch beim Speichern der Modelle hinzu, also wird es erwartet.

Nebenfrage: In meinem Admin-Tool werden diese 2 Felder nicht angezeigt. Wird das erwartet?

Da diese Felder automatisch hinzugefügt werden, werden sie nicht angezeigt.

Um dem hinzuzufügen, gab es, wie Synack sagte, eine Debatte über die Django-Mailingliste, um diese zu entfernen, weil sie "nicht gut entwickelt" und "ein Hack" ist.

Das Schreiben eines benutzerdefinierten Save () auf jedes meiner Modelle ist viel schmerzhafter als die Verwendung von auto_now

Natürlich müssen Sie es nicht in jedes Modell schreiben. Sie können es in ein Modell schreiben und andere davon erben.

Aber da auto_add und auto_now_add sind, würde ich sie verwenden, anstatt selbst eine Methode zu schreiben.

Für Django 1.1.

Ich habe das in meinem models.py:

class User(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

Wenn ich eine Zeile aktualisiere, bekomme ich:

[Sun Nov 15 02:18:12 2009] [error] /home/ptarjan/projects/twitter-meme/django/db/backends/mysql/base.py:84: Warning: Column 'created' cannot be null
[Sun Nov 15 02:18:12 2009] [error]   return self.cursor.execute(query, args)

Der relevante Teil meiner Datenbank ist:

  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,

Ist das ein Grund zur Besorgnis?

Nebenfrage: In meinem Admin-Tool werden diese beiden Felder nicht angezeigt. Wird das erwartet?


Ich denke, die einfachste (und vielleicht eleganteste) Lösung besteht darin, die Tatsache zu nutzen, dass Sie default eine aufrufbare Funktion festlegen können. Um das spezielle Handling von auto_now zu umgehen, können Sie das Feld einfach so deklarieren:

from django.utils import timezone
date_filed = models.DateField(default=timezone.now)

Es ist wichtig, dass Sie timezone.now() nicht verwenden, da der Standardwert nicht aktualisiert wird (dh der Standardwert wird nur beim Laden des Codes festgelegt). Wenn Sie sich häufig dabei befinden, können Sie ein benutzerdefiniertes Feld erstellen. Allerdings ist das schon ziemlich DRY, denke ich.


Ich habe eine Lösung gefunden

Wenn ich eine Modellklasse wie:

class MyModel(models.Model):
    time = models.DatetimeField(auto_now_add=True)
    time.editable = True

Dann wird dieses Feld auf meiner Admin-Seite erscheinen


Ich brauchte heute etwas Ähnliches bei der Arbeit. Der Standardwert ist timezone.now (). Er kann jedoch sowohl in den Admin- als auch in den Klassenansichten vererbt werden, die von FormMixin stammen. Für die Erstellung in meinem models.py erfüllte der folgende Code diese Anforderungen:

from __future__ import unicode_literals
import datetime

from django.db import models
from django.utils.functional import lazy
from django.utils.timezone import localtime, now

def get_timezone_aware_now_date():
    return localtime(now()).date()

class TestDate(models.Model):
    created = models.DateField(default=lazy(
        get_timezone_aware_now_date, datetime.date)()
    )

Für DateTimeField nehme ich an, dass die Funktion .date () von der Funktion entfernt wird und datetime.date in datetime.datetime oder besser in timezone.datetime geändert wird. Ich habe es nicht mit DateTime versucht, nur mit Date.


Über eine Nebenfrage: Wenn Sie diese Felder in admin sehen möchten (obwohl Sie sie nicht bearbeiten können), können readonly_fields Ihrer Admin-Klasse readonly_fields hinzufügen.

class SomeAdmin(ModelAdmin):
    readonly_fields = ("created","modified",)

Nun, das gilt nur für die neuesten Django-Versionen (glaube ich, 1.3 und höher)


auto_now=True hat in Django 1.4.1 nicht funktioniert, aber der folgende Code hat mich gerettet. Es ist für Zeitzone bewusste Datetime.

from django.utils.timezone import get_current_timezone
from datetime import datetime

class EntryVote(models.Model):
    voted_on = models.DateTimeField(auto_now=True)

    def save(self, *args, **kwargs):
        self.voted_on = datetime.now().replace(tzinfo=get_current_timezone())
        super(EntryVote, self).save(*args, **kwargs)

Basierend auf meinen bisherigen Erfahrungen mit Django ist auto_now_add fehlerhaft. Ich stimme jthanism zu - überschreibe die normale Save-Methode, es ist sauber und du weißt, was passiert. Erstellen Sie jetzt ein abstraktes Modell namens TimeStamped, um es trocken zu stellen:

from django.utils import timezone

class TimeStamped(models.Model):
    creation_date = models.DateTimeField(editable=False)
    last_modified = models.DateTimeField(editable=False)

    def save(self, *args, **kwargs):
        if not self.creation_date:
            self.creation_date = timezone.now()

        self.last_modified = timezone.now()
        return super(TimeStamped, self).save(*args, **kwargs)

    class Meta:
        abstract = True

Und dann, wenn Sie ein Modell mit diesem zeitauffälligen Verhalten wollen, nur Unterklasse:

MyNewTimeStampyModel(TimeStamped):
    field1 = ...

Wenn die Felder im Admin angezeigt werden sollen, entfernen Sie einfach die Option editable=False


Hier ist die Antwort, wenn Sie South verwenden und als Standard das Datum angeben möchten, an dem Sie das Feld zur Datenbank hinzufügen:

Wählen Sie Option 2 und dann: datetime.datetime.now ()

Sieht aus wie das:

$ ./manage.py schemamigration myapp --auto
 ? The field 'User.created_date' does not have a default specified, yet is NOT NULL.
 ? Since you are adding this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ? Please select a choice: 2
 ? Please enter Python code for your one-off default value.
 ? The datetime module is available, so you can do e.g. datetime.date.today()
 >>> datetime.datetime.now()
 + Added field created_date on myapp.User

Jedes Feld mit dem Attributsatz auto_now erbt ebenfalls auto_now editable=False und wird daher nicht im Admin- auto_now . Es wurde in der Vergangenheit darüber gesprochen, die Argumente auto_now und auto_now_add , und obwohl sie immer noch existieren, bin ich der Meinung, dass es besser ist, eine benutzerdefinierte save() -Methode zu verwenden .

Damit dies funktioniert, würde ich empfehlen, auto_now oder auto_now_add nicht zu verwenden und stattdessen eine eigene save() -Methode zu definieren, um sicherzustellen, dass das created Objekt nur dann aktualisiert wird, wenn die id nicht gesetzt ist (z. B. wenn das Objekt zum ersten Mal erstellt wird) Lassen Sie das Update jedes Mal ändern, wenn der Artikel gespeichert wird.

Ich habe genau das gleiche mit anderen Projekten gemacht, die ich mit Django geschrieben habe, und so würde Ihre save() wie folgt aussehen:

from django.utils import timezone

class User(models.Model):
    created     = models.DateTimeField(editable=False)
    modified    = models.DateTimeField()

    def save(self, *args, **kwargs):
        ''' On save, update timestamps '''
        if not self.id:
            self.created = timezone.now()
        self.modified = timezone.now()
        return super(User, self).save(*args, **kwargs)

Hoffe das hilft!

Als Antwort auf Kommentare bearbeiten:

Der Grund, warum ich einfach bei der Überladung von save() vs. vertraue auf diese Feldargumente bleibe, ist zweifach:

  1. Die oben genannten Höhen und Tiefen mit ihrer Zuverlässigkeit. Diese Argumente hängen stark davon ab, wie jeder Dateityp, mit dem Django zu interagieren weiß, ein Datums- / Zeitstempelfeld behandelt und zwischen jedem Release zu brechen und / oder zu wechseln scheint. (Was ich glaube, ist der Antrieb hinter dem Ruf, sie ganz zu entfernen).
  2. Die Tatsache, dass sie nur auf DateField, DateTimeField und TimeField funktionieren, und mit dieser Technik können Sie jeden Feldtyp automatisch jedes Mal aktualisieren, wenn ein Element gespeichert wird.
  3. Verwenden Sie django.utils.timezone.now() vs. datetime.datetime.now() , da es je nach den settings.USE_TZ ein TZ- datetime.datetime oder naives datetime.datetime Objekt datetime.datetime .

Um zu erklären, warum das OP den Fehler gesehen hat, weiß ich es nicht genau, aber es sieht so aus created es überhaupt nicht auto_now_add=True , obwohl auto_now_add=True . Für mich sticht es als Bug hervor und unterstreicht Punkt # 1 in meiner obigen kleinen Liste: auto_now und auto_now_add sind auto_now_add flockig.


Was Ihre Admin-Anzeige betrifft, sehen Sie diese Antwort .

Hinweis: auto_now und auto_now_add sind standardmäßig auf editierbar = False gesetzt, weshalb dies zutrifft.


Hier ist ein kleiner Test, der zeigt, dass das Zuführen der seed() -Methode mit demselben Argument das gleiche Pseudozufallsergebnis verursacht:

# testing random.seed()

import random

def equalityCheck(l):
    state=None
    x=l[0]
    for i in l:
        if i!=x:
            state=False
            break
        else:
            state=True
    return state


l=[]

for i in range(1000):
    random.seed(10)
    l.append(random.random())

print "All elements in l are equal?",equalityCheck(l)




python django datetime django-models django-admin