对于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,
这值得关注吗?
小问题:在我的管理工具中,这两个字段没有显示。这是意料之中的吗?
带有auto_now属性集的任何字段也将继承editable=False,因此不会显示在管理面板中。过去已经讨论过删除auto_now和auto_now_add参数,尽管它们仍然存在,但我认为最好使用自定义save()方法。
因此,为了使其正常工作,我建议不要使用auto_now或auto_now_add,而是定义自己的save()方法,以确保仅在未设置id时(例如当项目第一次创建时)才更新created,并在每次保存项目时更新修改它。
我用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()而不是依赖这些字段参数的原因有两个:
The aforementioned ups and downs with their reliability. These arguments are heavily reliant on the way each type of database that Django knows how to interact with treats a date/time stamp field, and seems to break and/or change between every release. (Which I believe is the impetus behind the call to have them removed altogether).
The fact that they only work on DateField, DateTimeField, and TimeField, and by using this technique you are able to automatically populate any field type every time an item is saved.
Use django.utils.timezone.now() vs. datetime.datetime.now(), because it will return a TZ-aware or naive datetime.datetime object depending on settings.USE_TZ.
为了解决OP看到错误的原因,我不确切地知道,但它看起来像创建的甚至没有被填充,尽管有auto_now_add=True。对我来说,这是一个明显的错误,并强调了我上面小列表中的第一条:auto_now和auto_now_add充其量是不可靠的。
这值得关注吗?
不,在保存模型时,Django会自动为你添加它,所以,这是意料之中的。
辅助问题:在我的管理工具中,这两个字段没有显示。这是意料之中的吗?
由于这些字段是自动添加的,所以不会显示它们。
为了补充上面的内容,正如synack所说,django邮件列表中一直有关于删除它的争论,因为它“设计得不好”,是“一个黑客”。
在我的每个模型上编写自定义save()比使用auto_now要痛苦得多
显然,你不需要对每个模型都写。您可以将它写入一个模型,并从它继承其他模型。
但是,由于存在auto_add和auto_now_add,我宁愿使用它们,而不是自己尝试编写方法。
但我想指出,公认答案中所表达的观点有些过时。根据最近的讨论(django bug #7634和#12785),auto_now和auto_now_add不会消失,即使你去看最初的讨论,你也会在自定义保存方法中发现强烈的反对RY(如DRY)的论点。
已经提供了一个更好的解决方案(自定义字段类型),但还没有获得足够的动力将其纳入django。你可以用三行写你自己的(这是Jacob Kaplan-Moss的建议)。
from django.db import models
from django.utils import timezone
class AutoDateTimeField(models.DateTimeField):
def pre_save(self, model_instance, add):
return timezone.now()
#usage
created_at = models.DateField(default=timezone.now)
updated_at = AutoDateTimeField(default=timezone.now)
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)
你可以使用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_now_add将导致错误。
下面是Django默认DateTimeField的代码。Pre_save withauto_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的经验,auto_now_add是有bug的。我同意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
然后,当你想要一个具有这种时间戳行为的模型时,只需子类:
MyNewTimeStampyModel(TimeStamped):
field1 = ...
如果您希望字段显示在管理中,那么只需删除editable=False选项
我今天工作也需要类似的东西。默认值是时区.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。日期到日期时间。Datetime或者更好的timezone.datetime。我没有在DateTime上尝试过,只在Date上尝试过。