python - template - django tutorial




Django auto_now und auto_now_add (8)

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?


Ü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)


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

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


Sie können auto_now timezone.now() für created und auto_now für modified verwenden:

from django.utils import timezone
class User(models.Model):
    created = models.DateTimeField(default=timezone.now())
    modified = models.DateTimeField(auto_now=True)

Wenn Sie einen benutzerdefinierten Primärschlüssel anstelle des standardmäßigen auto_now_add auto- increment int , führt auto_now_add zu einem Fehler.

Hier ist der Code von Djangos Standard DateTimeField.pre_save mit auto_now und auto_now_add :

def pre_save(self, model_instance, add):
    if self.auto_now or (self.auto_now_add and add):
        value = timezone.now()
        setattr(model_instance, self.attname, value)
        return value
    else:
        return super(DateTimeField, self).pre_save(model_instance, add)

Ich bin mir nicht sicher, was der Parameter add soll. Ich hoffe es wird so etwas wie:

add = True if getattr(model_instance, 'id') else False

Der neue Datensatz hat keine Attr- id , sodass getattr(model_instance, 'id') False getattr(model_instance, 'id') dazu führt, dass kein Wert im Feld gesetzt wird.


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.





django-admin