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_now
和 auto_now_add
。
来自文档:
DateField.auto_now
在每次保存对象时自动将字段设置为现在。(这意味着它也是第一次创建时)
DateField.auto_now_add
在第一次创建对象时自动将字段设置为现在。
编辑:
如果您希望在首次创建对象时将 updated_at
字段设为 null
,您只需将 null=True
与 auto_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_at
的null
值,并在更新字段后拥有正确的时间值。
我认为同样的方式你也可以将更新作者分配给updated_by
。
【讨论】:
以上是关于Django auto_now 行为的主要内容,如果未能解决你的问题,请参考以下文章
django1.5.4数据库,auto_now时间不能自动更新
Django auto_now 与 auto_now_add
django model:auto_now_add 和 auto_now