Django auto_now 行为

Posted

技术标签:

【中文标题】Django auto_now 行为【英文标题】:Django auto_now behaviour 【发布时间】:2018-02-01 03:14:45 【问题描述】:

我有以下型号:

class MetaData(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, auto_now=False)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
                                   related_name='%(app_label)s_%(class)s_created_by')
    updated_at = models.DateTimeField(auto_now_add=False, auto_now=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
                                   related_name='%(app_label)s_%(class)s_updated_by')

update_at 字段也在创建时以一个值完成,而不是为空。我希望只有在第一次保存/创建之后才会有一个值。

我做错了吗?

【问题讨论】:

【参考方案1】:

在 Django 中,您同时拥有 auto_nowauto_now_add

来自文档:

DateField.auto_now

在每次保存对象时自动将字段设置为现在。(这意味着它也是第一次创建时)

DateField.auto_now_add

在第一次创建对象时自动将字段设置为现在

编辑

如果您希望在首次创建对象时将 updated_at 字段设为 null,您只需将 null=Trueauto_now=True 一起传递给 DateTimeField

class MetaData(models.Model):
    # ...
    updated_at = models.DateTimeField(auto_now=True, null=True)
    # ...

【讨论】:

有什么办法可以覆盖这个行为? @user3541631 我刚刚用可能的解决方案编辑了我的答案。 @user3541631 最好看看这个关于使用 auto_now 和 auto_now_add ***.com/questions/1737017/… @wencakisa 你确定“auto_now=True, null=True”会起作用吗?刚刚在 Postgres DB 上测试过它并没有。我也看不到 Postgress 上的实现是如何实现的 @zoran,正如您已经指出的那样,我还确认 updated_at = models.DateTimeField(auto_now=True, null=True) 确实 not(!) 工作。每次保存对象时都会设置它(包括创建记录时)。注意:使用 django 3.0.4 测试【参考方案2】:

还有另一种方法可以做到这一点。最好按照wencakisa 的建议做,除非您在模型中使用save 方法。

正如documentation中所写的那样

该字段仅在调用 Model.save() 时自动更新。这 以其他方式更新其他字段时,字段未更新 例如 QuerySet.update(),尽管您可以为 像这样的更新中的字段。

所以,即使你使用auto_now,但是调用save方法例如生成一个slug地址,时间也会在对象创建时分配给auto_now的字段。

如何处理这种情况并在创建之后和更新之前将字段updated_at 保留为null 值?

例如,如果您使用的是 UpdateView,请在 form_valid 方法中指定时间。

models.py

class MetaData(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, auto_now=False)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
                                   related_name='%(app_label)s_%(class)s_created_by')
    updated_at = models.DateTimeField(null=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
                                   related_name='%(app_label)s_%(class)s_updated_by')

    def save(self, *args, **kwargs):
        # SOMETHING HERE
        super().save(*args, **kwargs)

views.py

class UpdateMetaData(generic.UpdateView):
    # SOMETHING HERE

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.updated_at = timezone.now()
        self.object.save()
        return super().form_valid(form)

您应该在创建后拥有updated_atnull 值,并在更新字段后拥有正确的时间值。

我认为同样的方式你也可以将更新作者分配给updated_by

【讨论】:

以上是关于Django auto_now 行为的主要内容,如果未能解决你的问题,请参考以下文章

django1.5.4数据库,auto_now时间不能自动更新

Django的auto_now=True没有自动更新

Django auto_now 与 auto_now_add

django model:auto_now_add 和 auto_now

python Django:如何使用auto_now = True手动设置/更新DateTimeField字段

django模型中auto_now和auto_now_add的区别