Django auto сейчас и авто теперь добавить

Для Django 1.1.

у меня есть это в моем models.py:

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

при обновлении строки я получаю:

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

соответствующая часть моей базы данных:

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

это повод для беспокойства?

боковой вопрос: в моем инструменте администратора эти два поля не отображаются. Это ожидаемо?

12 ответов


любое поле с auto_now набор атрибутов также наследует editable=False и, следовательно, не будет отображаться в панели администратора. В прошлом были разговоры о том, чтобы сделать auto_now и auto_now_add аргументы уходят, и хотя они все еще существуют, я чувствую, что вам лучше просто использовать таможни save() метод.

Итак, чтобы сделать эту работу правильно, я бы рекомендовал не использовать auto_now или auto_now_add и вместо этого определите свой собственный save() метод, чтобы убедиться в том, что created обновляется только если id не установлен (например, когда элемент впервые создан), и его обновление modified каждый раз, когда элемент сохраняется.

я сделал то же самое с другими проектами, которые я написал с помощью Django, и поэтому ваш save() будет выглядеть так:

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)

надеюсь, что это помогает!

редактировать в ответ на комментарии:

причина, по которой я просто придерживаюсь перегрузка save() против полагаться на эти аргументы поля в два раза:

  1. вышеупомянутые взлеты и падения с их надежностью. Эти аргументы в значительной степени зависят от того, как каждый тип базы данных, с которой Django знает, как взаимодействовать, обрабатывает поле даты/времени и, похоже, ломается и/или изменяется между каждым выпуском. (Что, я считаю, является стимулом для призыва к их полному удалению).
  2. тот факт, что они работают только на DateField, DateTimeField и TimeField, и с помощью этого метода вы можете автоматически заполнять любой тип поля при каждом сохранении элемента.
  3. использовать django.utils.timezone.now() и datetime.datetime.now(), потому что он вернет TZ-aware или наивный datetime.datetime объект в зависимости от settings.USE_TZ.

чтобы решить, почему OP увидел ошибку, я точно не знаю, но это похоже на created даже не заселяется вообще, несмотря на наличие auto_now_add=True. Для меня он выделяется как ошибка, и товар подчеркивает #1 в моем маленьком списке выше:auto_now и auto_now_add в лучшем случае шелушатся.


Бах... Недостаточно репутации, чтобы комментировать... Но я хотел отметить, что мнение, выраженное в принятом ответе, несколько устарело. Согласно более поздним обсуждениям (Django bugs #7634 и #12785), auto_now и auto_now_add никуда не денутся, и даже если вы идете к оригинальный обсуждения, вы найдете сильные аргументы против RY (как в DRY) в пользовательских методах сохранения.

было предложено лучшее решение (пользовательские типы полей), но не получили достаточного импульса, чтобы сделать его в django. Вы можете написать свой собственный в трех строках (это предложение Джейкоба Каплана-Мосса).

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)

говоря о побочном вопросе: если вы хотите увидеть эти поля в admin (хотя, вы не сможете их редактировать), вы можете добавить readonly_fields в свой класс admin.

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

Ну, это относится только к последним версиям Django (я считаю, 1.3 и выше)


Я думаю, что самое простое (и, возможно, самое элегантное) решение здесь-использовать тот факт, что вы можете установить default вызываемому. Итак, чтобы обойти специальную обработку администратора auto_now, вы можете просто объявить поле следующим образом:

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

важно, чтобы вы не использовали timezone.now() поскольку значение по умолчанию не будет обновляться (т. е. значение по умолчанию устанавливается только при загрузке кода). Если вы часто это делаете, вы можете создать настраиваемое поле. Однако, это довольно сухо я уже думаю.


основываясь на том, что я прочитал и мой опыт работы с Django до сих пор, auto_now_add глючит. Я согласен с jthanism --- переопределить нормальный метод сохранения, он чист, и вы знаете, что происходит. Теперь, чтобы сделать его сухим, создайте абстрактную модель под названием 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

и затем, когда вы хотите модель, которая имеет это время-stampy поведение, просто подкласс:

MyNewTimeStampyModel(TimeStamped):
    field1 = ...

Если вы хотите, чтобы поля отображались в admin, просто удалите editable=False опции


Я нашел решение

Если у меня есть класс модели, как:

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

тогда это поле появится на моей странице изменения администратора


можно использовать timezone.now() для создан и auto_now изменен на:

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

если вы используете пользовательский первичный ключ вместо auto- increment int, auto_now_add приведет к ошибке.

вот код по умолчанию Django DateTimeField.pre_save Сauto_now и 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)

я не уверен, что параметр add есть. Я надеюсь, что это будет что-то типа:

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

новая запись не будет имейте attr id, так что getattr(model_instance, 'id') вернет False приведет к не заданию какого-либо значения в поле.


это повод для беспокойства?

нет, Django автоматически добавляет его для вас при сохранении модели, Итак, предполагается.

боковой вопрос: в моем инструменте администратора эти 2 поля не отображаются. Это ожидаемо?

поскольку эти поля добавляются автоматически, они не отображаются.

чтобы добавить к вышесказанному, как сказал synack, были дебаты по списку рассылки django, чтобы удалить это, потому что это "не разработан хорошо" и является "Хак"

написание пользовательского save () на каждой из моих моделей намного больнее, чем использование auto_now

очевидно, вам не нужно писать его для каждой модели. Вы можете записать его в одну модель и унаследовать от нее другие.

, а как auto_add и auto_now_add есть, я бы использовал их, а не пытался написать метод сам.


Что касается дисплея администратора, см. ответ.

Примечание: auto_now и auto_now_add имеют значение editable=False по умолчанию, поэтому это применимо.


Мне нужно что-то подобное сегодня на работе. Значение по умолчанию часовой пояс.теперь (), но редактируется как в представлениях admin, так и в классах, наследуемых от FormMixin, поэтому для созданных в моем models.py эти требования были выполнены следующим кодом:

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

для DateTimeField, я думаю, удалите .date () из функции и изменить datetime.дата в datetime.datetime или лучше часовой пояс.значение datetime. Я не пробовал это с DateTime, только с Date.


auto_now=True не работал для меня в Django 1.4.1, но приведенный ниже код спас меня. Это для часового пояса, знающего 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)

вот ответ, если вы используете south и хотите по умолчанию указать дату добавления поля в базу данных:

Выберите вариант 2 затем:datetime.значение datetime.сейчас()

выглядит так:

$ ./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