У меня такая модель db:
from datetime import datetime
class TermPayment(models.Model):
# cut out some fields, non relevant to the question
date = models.DateTimeField(default=datetime.now(), blank=True)
И когда добавлен новый экземпляр:
tp = TermPayment.objects.create(**kwargs)
У меня проблема: все записи в базе данных имеют одинаковое значение в поле даты - дату первого платежа. После перезапуска сервера - одна запись имеет новую дату, а другие - то же, что и первая. Похоже, что используется кеш данных, но я не могу найти где.
: mysql 5.1.25
django v1.1.1
похоже, что datetime.now()
оценивается, когда модель определена, а не каждый раз, когда вы добавляете запись.
В Django есть функция, чтобы выполнить то, что вы пытаетесь сделать уже:
date = models.DateTimeField(auto_now_add=True, blank=True)
или
date = models.DateTimeField(default=datetime.now, blank=True)
Разница между вторым примером и тем, что у вас сейчас есть, - это отсутствие круглых скобок. Передавая datetime.now
без круглых скобок, вы передаете фактическую функцию, которая будет вызываться каждый раз, когда будет добавлена запись. Если вы передадите его datetime.now()
, то вы просто оцениваете функцию и передаете ей возвращаемое значение.
Дополнительная информация доступна в Django ссылка на поле модели
expiry = models.DateTimeField(default=datetime.now + timedelta(days=30))
Вместо использования datetime.now
вы должны действительно использовать from django.utils.timezone import now
django.utils.timezone.now
auto_now_add
с помощью auto_now_add
(которое auto_now_add
часовой пояс), вы можете получить неправильные вычисления из-за различий в часовых поясах.
Из документации в поле по умолчанию модели django:
Значение по умолчанию для поля. Это может быть значение или вызываемый объект. Если он вызывается, он будет вызываться каждый раз, когда создается новый объект.
Следовательно, следующее должно работать:
date = models.DateTimeField(default=datetime.now,blank=True)
default
( django-chinese-docs-14.readthedocs.io/en/latest/ref/models/… )
У Дэвида был правильный ответ. Скобка() делает ее так, что вызываемый timezone.now() вызывается каждый раз, когда модель оценивается. Если вы удалите() из timezone.now() (или datetime.now(), если используете объект наивного datetime), чтобы сделать это именно так:
default=timezone.now
Тогда он будет работать так, как вы ожидаете:
Новые объекты получат текущую дату при их создании, но дата не будет переопределяться каждый раз, когда вы делаете manage.py makemigrations/migrate.
Я просто столкнулся с этим. Огромное спасибо Дэвиду.
datetime.now()
оценивается при создании класса, а не при добавлении новой записи в базу данных.
Чтобы достичь того, что вы хотите, определите это поле как:
date = models.DateTimeField(auto_now_add=True)
Таким образом, поле date
будет установлено на текущую дату для каждой новой записи.
Ответ на этот вопрос на самом деле неверен.
Автозаполнение значения (auto_now/auto_now_add не совпадает с по умолчанию). Значением по умолчанию будет то, что пользователь видит, если это новый объект. Обычно я делаю следующее:
date = models.DateTimeField(default=datetime.now, editable=False,)
Убедитесь, что если вы пытаетесь представить это на странице администратора, вы указываете его как "read_only" и ссылаетесь на имя поля
read_only = 'date'
Опять же, я делаю это, так как мое значение по умолчанию обычно не редактируется, а страницы Admin игнорируют non-editables, если не указано иное. Однако существует определенная разница между установкой значения по умолчанию и внедрением auto_add, который является ключевым здесь. Проверьте это!
datetime.now()
оценивается один раз, когда ваш экземпляр создается. Попробуйте удалить круглую скобку, чтобы возвращалась функция datetime.now
и THEN оценивалась. У меня была такая же проблема с установкой значений по умолчанию для моего DateTimeField
и написала мое решение здесь.
Из справочника языка Python под Определения функций:
Значения параметров по умолчанию оцениваются при выполнении определения функции. Это означает, что выражение оценивается один раз, когда функция определена, и что для каждого вызова используется то же самое "предварительно вычисленное" значение.
К счастью, у Django есть способ сделать то, что вы хотите, если вы используете аргумент auto_now
для DateTimeField
:
date = models.DateTimeField(auto_now=True)
См. документы Django для DateTimeField.
default=datetime.now
- note, без вызова, как вnow()
Не стандарт для DateTimeField, но ... удобно в любом случае.