Django auto_now 和 auto_now_add

2025-02-14 09:49:00
admin
原创
46
摘要:问题描述:对于 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大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用