Django auto_now 和 auto_now_add

2025-02-14 09:49:00
admin
原创
49
摘要:问题描述:对于 Django 1.1。我的 models.py 中有这个:class User(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(au...

问题描述:

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

这是否值得担忧?

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


解决方案 1:

任何具有该auto_now属性集的字段也将继承editable=False,因此不会显示在管理面板中。过去曾有人讨论过让auto_nowauto_now_add参数消失,尽管它们仍然存在,但我觉得你最好只使用自定义save()方法。

因此,为了使其正常工作,我建议不要使用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()而不是依赖这些字段参数的原因有两个:

  1. 上述可靠性方面存在着优缺点。这些论点在很大程度上依赖于 Django 知道如何与之交互的每种类型的数据库处理日期/时间戳字段的方式,并且似乎在每次发布之间都会中断和/或更改。(我认为这是呼吁将它们全部删除的动力)。

  2. 事实上,它们只适用于 DateField、DateTimeField 和 TimeField,并且通过使用此技术,您可以在每次保存项目时自动填充任何字段类型。

  3. 使用django.utils.timezone.now()vs. datetime.datetime.now(),因为它将datetime.datetime根据 返回 TZ 感知或简单对象settings.USE_TZ

至于为什么 OP 看到错误,我不太清楚,但看起来好像created根本没有被填充,尽管有auto_now_add=True。对我来说,这是一个错误,并强调了我上面小列表中的第 1 项: auto_now并且auto_now_add充其量是不稳定的。

解决方案 2:

但我想指出的是,接受的答案中表达的观点有些过时了。根据最近的讨论(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)

解决方案 3:

谈论一个附带问题:如果您想在管理员中看到这些字段(但是,您将无法编辑它),您可以将其添加readonly_fields到您的管理员类别中。

class SomeAdmin(ModelAdmin):
    readonly_fields = ("created","modified",)

嗯,这仅适用于最新的 Django 版本(我相信 1.3 及以上版本)

解决方案 4:

我认为这里最简单(也可能是最优雅)的解决方案是利用您可以设置为可调用的事实default。因此,为了绕过管理员对 auto_now 的特殊处理,您可以像这样声明该字段:

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

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

解决方案 5:

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

解决方案 6:

如果你像这样改变模型类:

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

然后这个字段就会出现在我的管理更改页面中

解决方案 7:

根据我读过的内容以及迄今为止使用 Django 的经验,auto_now_add 存在错误。我同意 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选项

解决方案 8:

这是否值得担忧?

不,Django 在保存模型时会自动为您添加它,所以这是预料之中的。

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

由于这些字段是自动添加的,因此不会显示。

补充一下,正如 synack 所说,django 邮件列表中曾有一场关于删除该功能的争论,因为它“设计得不好”并且是“黑客行为”

在我的每个模型上编写自定义 save() 比使用 auto_now 要痛苦得多

显然你不必将它写入每个模型。你可以将它写入一个模型并从中继承其他模型。

但是,由于auto_addauto_now_add存在,我会使用它们,而不是尝试自己编写方法。

解决方案 9:

至于您的管理显示,请参阅此答案。

注意:auto_now和默认auto_now_add设置为editable=False,这就是适用的原因。

解决方案 10:

我今天在工作中需要类似的东西。默认值为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.datedatetime.datetimetimezone.datetimeDateTimeDate`

解决方案 11:

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:

您可以使用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 intauto_now_add将导致错误。

以下是 Django 默认的DateTimeField.pre_save的代码,其中包含auto_nowauto_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 ,导致不会在字段中设置任何值。

解决方案 13:

您可以使用此代码技术来创建 [创建日期](在创建行时自动保存日期并且从不更新每次更新的日期和时间)和 [更新日期](每次更新行时更改日期和时间)。

from django.db import models
from django.utils.timezone import now

class Artical(models.Model):
    
    creation = models.DateTimeField(null=True, default=None, blank=True)
    updation = models.DateTimeField(null=True,default=None,blank=True)

    def save(self, *args, **kwargs):
       
        if not self.creation:
            self.creation = now()

        self.updation = now()

        super(Artical, self).save(*args, **kwargs)

解决方案 14:

关于 update_fields 已经有一些评论,但它没有包含在答案中,所以我在这里做了一个重要的修订。默认情况下,当 django 保存一个实例时,它会保存该实例中的每个字段。当只有一个字段被更新时,这是浪费的,更经济的方法是只保存被更改的字段。这是在 django 中使用update_fields参数完成的,如下所示:

qt = QueuedTask.objects.create()
qt.status = PENDING
qt.save(update_fields=['status'])

现在您的保存方法应该考虑到这一点,否则在上面的保存中,last_modified字段也不会被保存(请注意,我不确定是否创建,但是因为您可以创建一个新实例,并使用带有更新字段的保存方法,所以我也在保存中包含了条件):

def save(self, *args, **kwargs):
    if self.id is None:
        self.created_on = timezone.now()
        update_fields = kwargs.get('update_fields')
        if update_fields is not None and 'created_on' not in update_fields:
            update_fields += ['created_on']
    else:
        self.last_modified = timezone.now()
        update_fields = kwargs.get('update_fields')
        if update_fields is not None and 'last_modified' not in update_fields:
            update_fields += ['last_modified']
    return super(QueuedTask, self).save(*args, **kwargs)

解决方案 15:

如文档中所述:

使用 update() 还可以防止出现竞争条件,即在加载对象和调用 save() 之间的短时间内数据库中可能会发生某些变化。最后,请注意 update() 在 SQL 级别执行更新,因此不会调用模型上的任何 save() 方法,也不会发出 pre_save 或 post_save 信号(这是调用 Model.save() 的结果)。如果要更新具有自定义 save() 方法的模型的一组记录,请循环遍历它们并调用 save(),如下所示:

for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1590  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1361  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   18  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   18  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   19  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用