对于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,

这值得关注吗?

小问题:在我的管理工具中,这两个字段没有显示。这是意料之中的吗?


当前回答

如果你像这样修改你的模型类:

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

然后这个字段将显示在我的管理更改页面

其他回答

带有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充其量是不可靠的。

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)

如果你像这样修改你的模型类:

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

然后这个字段将显示在我的管理更改页面

我认为这里最简单(也许也是最优雅)的解决方案是利用可以将default设置为可调用对象这一事实。所以,为了避开管理员对auto_now的特殊处理,你可以像这样声明字段:

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

重要的是,不要使用timezone.now(),因为默认值不会更新(即,只有在加载代码时才设置默认值)。如果您发现自己经常这样做,您可以创建一个自定义字段。然而,我认为这已经相当DRY了。

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将设置某人修改反馈的时间。