Django auto now I auto now dodaj

Dla Django 1.1.

Mam to w moim models.py:

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

Podczas aktualizacji wiersza dostaję:

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

Odpowiednia część mojej bazy danych to:

  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
Czy to powód do niepokoju?

Pytanie poboczne: w moim narzędziu administracyjnym te dwa pola się nie pojawiają. Czy to jest oczekiwane?

Author: Peter Mortensen, 2009-11-15

12 answers

Dowolne pole z auto_now atrybut set będzie również dziedziczył editable=False i dlatego nie pojawi się w panelu administracyjnym. W przeszłości mówiono o zrobieniu auto_now i auto_now_add argumenty znikają i chociaż nadal istnieją, czuję, że lepiej będzie użyć niestandardowej metody save() .

Więc, aby to działało poprawnie, zalecałbym nie używać auto_now lub auto_now_add i zamiast tego zdefiniować własną metodę save(), aby upewnić się, że created jest tylko zaktualizowano, jeśli id nie jest ustawione (np. gdy element jest tworzony po raz pierwszy), i należy zaktualizować modified za każdym razem, gdy element jest zapisywany.

Zrobiłem dokładnie to samo z innymi projektami, które napisałem używając Django, więc twoje save() wyglądałoby tak:

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)
Mam nadzieję, że to pomoże!

Edit in response to comments:

Powód, dla którego trzymam się przeciążania save() vs. opieranie się na tych argumentach pola jest dwojaki:

  1. The wyżej wymienione wzloty i upadki z ich niezawodnością. Argumenty te są w dużym stopniu zależne od sposobu, w jaki każdy typ bazy danych, z którą Django wie, jak wchodzić w interakcje, traktuje pole znacznika daty/czasu i wydaje się łamać i/lub zmieniać pomiędzy każdym wydaniem. (Co moim zdaniem jest impulsem do wezwania do ich całkowitego usunięcia).
  2. fakt, że działają tylko na DateField, DateTimeField i TimeField, a dzięki tej technice jesteś w stanie automatycznie wypełnić dowolny typ pola za każdym razem, gdy element jest zapisywany.
  3. użyj django.utils.timezone.now() vs. datetime.datetime.now(), ponieważ zwróci obiekt świadomy TZ lub naiwny datetime.datetime w zależności od settings.USE_TZ.

Aby wyjaśnić, dlaczego OP widział błąd, Nie wiem dokładnie, ale wygląda na to, że created nie jest w ogóle zaludniony, mimo że ma auto_now_add=True. Dla mnie wyróżnia się jako bug i podkreśla punkt #1 na mojej małej liście powyżej: auto_now i auto_now_add są w najlepszym razie flaky.

 283
Author: jathanism,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-04 02:43:00

Bah... Za mało reputacji, by komentować... Chciałem jednak zaznaczyć, że opinia wyrażona w przyjętej odpowiedzi jest nieco przestarzała. Według nowszych dyskusji (django bugs #7634 oraz #12785), auto_now i auto_now_add nigdzie się nie wybierają, a nawet jeśli przejdziesz do oryginalnej dyskusji, znajdziesz mocne argumenty przeciwko ry (jak w DRY) w niestandardowych metodach zapisu.

Zaproponowano lepsze rozwiązanie (niestandardowe typy pól), ale nie nabierał rozpędu, żeby dostać się do django. Możesz napisać swój własny w trzech linijkach (to sugestia Jacoba Kaplana-Moss' a).

class AutoDateTimeField(models.DateTimeField):
    def pre_save(self, model_instance, add):
        return datetime.datetime.now()

#usage
created_at = models.DateField(default=timezone.now)
updated_at = models.AutoDateTimeField(default=timezone.now)
 133
Author: Shai Berger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-10 20:06:23

Mówiąc o pytaniu pobocznym: jeśli chcesz zobaczyć te pola w admin (choć nie będziesz mógł ich edytować), możesz dodać readonly_fields do swojej klasy admin.

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

Cóż, dotyczy to tylko najnowszych wersji Django (wierzę, 1.3 i powyżej)

 26
Author: DataGreed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-25 09:25:41

Myślę, że najprostszym (i może najbardziej eleganckim) rozwiązaniem tutaj jest wykorzystanie faktu, że można ustawić default do wywołania. Tak więc, aby ominąć specjalną obsługę auto_now przez admina, możesz po prostu zadeklarować pole w następujący sposób:

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

Ważne jest, aby nie używać timezone.now(), ponieważ wartość domyślna nie będzie aktualizowana(tzn. wartość domyślna zostanie ustawiona dopiero po załadowaniu kodu). Jeśli często to robisz, możesz utworzyć niestandardowe pole. Jednak, to jest dość suche już myślę.

 17
Author: Josh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-10 16:49:08

Bazując na tym, co przeczytałem i moim dotychczasowym doświadczeniu z Django, auto_now_add jest buggy. Zgadzam się z jthanism - - - Obejmij normalną metodę save jest czysta i wiesz co to jest. Teraz, aby wyschnąć, stwórz abstrakcyjny model o nazwie TimeStamped:

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

I wtedy, gdy chcesz model, który ma takie zachowanie, wystarczy podklasa:

MyNewTimeStampyModel(TimeStamped):
    field1 = ...

Jeśli chcesz, aby pola były wyświetlane w panelu administracyjnym, Usuń opcję editable=False

 12
Author: Edward Newell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-03 22:18:00

Znalazłem rozwiązanie

Jeśli mam klasę modelową typu:

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

Wtedy to pole pojawi się na mojej stronie zmiany administratora

 12
Author: Eric Zheng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-20 20:36:38

Możesz użyć timezone.now() dla stworzonych i auto_now dla zmodyfikowanych:

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

Jeśli używasz niestandardowego klucza podstawowego zamiast domyślnego auto- increment int, auto_now_add doprowadzi do pluskwy.

Oto kod domyślnego DateTimeField Django.pre_save z auto_now i 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)

Nie jestem pewien, jaki jest parametr add. Mam nadzieję, że będzie to coś w stylu:

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

Nowy rekord nie będzie miał attr id, więc getattr(model_instance, 'id') zwróci False spowoduje, że nie ustawianie dowolnej wartości w polu.

 5
Author: simple_human,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-01 03:04:17
Czy to powód do niepokoju?

Nie, Django automatycznie dodaje go dla Ciebie podczas zapisywania modeli, więc jest to oczekiwane.

Pytanie poboczne: w moim narzędziu administracyjnym te 2 Pola się nie pojawiają. Czy to jest oczekiwane?

Ponieważ te pola są dodawane automatycznie, nie są wyświetlane.

Aby dodać do powyższego, jak powiedział synack, odbyła się debata na liście dyskusyjnej django, aby to usunąć, ponieważ jest "nie zaprojektowana dobrze" i jest " a hack "

Pisanie niestandardowego save () na każdym z moich modeli jest o wiele bardziej bolesne niż używanie auto_now

Oczywiście nie musisz tego pisać do każdej modelki. Możesz zapisać go do jednego modelu i dziedziczyć z niego inne.

Ale ponieważ istnieją auto_add i auto_now_add, użyłbym ich zamiast próbować samemu napisać metodę.

 4
Author: Lakshman Prasad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-15 13:09:26

Jeśli chodzi o wyświetlanie admina, zobacz tę odpowiedź .

Uwaga: auto_now i auto_now_add są domyślnie ustawione na editable = False, dlatego ma to zastosowanie.

 2
Author: jlovison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:45

Potrzebowałam dziś czegoś podobnego w pracy. Domyślną wartością jest strefa czasowa.now (), ale edytowalne zarówno w widokach admin jak i class dziedziczących z FormMixin, więc dla utworzonych w moim models.py następujący kod spełniał te wymagania:

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

Dla DateTimeField, chyba usunąć .date () z funkcji i zmień datetime.od daty do daty.datetime lub lepsza Strefa czasowa.datetime. Nie próbowałem tego z DateTime, tylko z Date.

 2
Author: Tiphareth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-26 15:21:37

auto_now=True nie zadziałało u mnie w Django 1.4.1, ale poniższy kod mnie uratował. To dla timezone aware 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)
 1
Author: Ryu_hayabusa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-01 03:02:48

Oto odpowiedź, jeśli używasz south i chcesz ustawić domyślną datę dodania pola do bazy danych:

Wybierz opcję 2 następnie: datetime.datetime.teraz()

Wygląda tak:

$ ./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
 -1
Author: Jeff Hoye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-21 14:46:11