对于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,
这是值得关注的吗?
附带问题:在我的管理工具中,这两个字段没有显示出来。这是预期的吗?
答案 0 :(得分:321)
设置了auto_now
属性的任何字段也将继承editable=False
,因此不会显示在管理面板中。过去一直有人谈论让auto_now
和auto_now_add
论点消失,尽管它们仍然存在,但我觉得你最好只使用custom save()
method。
因此,要使其正常运行,我建议您不要使用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()
与依赖这些字段参数的原因有两个:
django.utils.timezone.now()
与datetime.datetime.now()
,因为它会返回TZ感知或天真的datetime.datetime
对象,具体取决于settings.USE_TZ
。为了解决OP看到错误的原因,我不确切地知道,但看起来created
甚至根本没有填充,尽管auto_now_add=True
。对我而言,它突出显示为一个错误,并在我上面的小清单中强调了第1项:auto_now
和auto_now_add
充其量只是片状。
答案 1 :(得分:152)
答案 2 :(得分:29)
谈论一个附带问题:如果您想在管理员中看到这些字段(但是,您将无法对其进行编辑),则可以将readonly_fields
添加到您的管理类。
class SomeAdmin(ModelAdmin):
readonly_fields = ("created","modified",)
嗯,这仅适用于最新的Django版本(我相信,1.3及以上版本)
答案 3 :(得分:23)
我认为这里最简单(也可能是最优雅)的解决方案是利用您可以将default
设置为可调用的事实。因此,为了解决管理员对auto_now的特殊处理,你可以像这样声明字段:
from django.utils import timezone
date_filed = models.DateField(default=timezone.now)
重要的是不要使用timezone.now()
,因为默认值不会更新(即,只有在加载代码时才会设置默认值)。如果你发现自己做了很多,你可以创建一个自定义字段。但是,我觉得这已经很干了。
答案 4 :(得分:17)
如果你改变你的模型类:
class MyModel(models.Model):
time = models.DateTimeField(auto_now_add=True)
time.editable = True
然后,此字段将显示在我的管理员更改页面
中答案 5 :(得分:12)
根据我所读到的内容以及到目前为止我对Django的体验,auto_now_add是错误的。我同意jthanism ---覆盖正常的保存方法,它很干净,你知道什么是hapenning。现在,为了让它变干,创建一个名为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
然后,当你想要一个具有这种时间戳行为的模型时,只需要子类:
MyNewTimeStampyModel(TimeStamped):
field1 = ...
如果您希望字段显示在管理员中,则只需删除editable=False
选项
答案 6 :(得分:5)
这是值得关注的吗?
不,Django会在保存模型时自动为您添加它,因此,它是预期的。
附带问题:在我的管理工具中,这两个字段没有显示出来。这是预期的吗?
由于这些字段是自动添加的,因此不会显示它们。
除此之外,正如synack所说,django邮件列表上有一个争论要删除它,因为它“设计得不好”并且是“黑客”
在我的每个模型上编写自定义save()比使用auto_now
要痛苦得多
显然,您不必将其写入每个模型。您可以将其写入一个模型并从中继承其他模型。
但是,当auto_add
和auto_now_add
存在时,我会使用它们而不是尝试自己编写方法。
答案 7 :(得分:4)
class Feedback(models.Model):
feedback = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
在这里,我们创建并更新了列,这些列在创建时以及有人修改反馈时都会带有时间戳。
auto_now_add 将设置创建实例的时间,而 auto_now 将设置有人修改其反馈的时间。
答案 8 :(得分:2)
对于您的管理员显示,请参阅this answer。
注意:auto_now
和auto_now_add
默认设置为editable=False
,这就是适用的原因。
答案 9 :(得分:2)
您可以对已创建的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
新记录不会有
id
,因此getattr(model_instance, 'id')
将返回False将导致未在字段中设置任何值。
答案 10 :(得分:2)
我今天在工作中需要类似的东西。默认值为timezone.now()
,但在继承自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.date
更改为datetime.datetime
或更好timezone.datetime
。我没有使用DateTime
尝试使用Date
。
答案 11 :(得分:1)
auto_now=True
在Django 1.4.1中没有为我工作,但下面的代码救了我。这是时区感知日期时间。
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)
答案 12 :(得分:-1)
如果您使用的是南方,并且您希望默认使用将该字段添加到数据库的日期,则答案如下:
选择 2 选项 然后: datetime.datetime.now()
看起来像这样:
$ ./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