【问题标题】:Django datetime issues (default=datetime.now())Django 日期时间问题(默认=datetime.now())
【发布时间】:2011-02-15 19:59:15
【问题描述】:

我有以下数据库模型:

from datetime import datetime    

class TermPayment(models.Model):
    # I have excluded fields that are irrelevant to the question
    date = models.DateTimeField(default=datetime.now(), blank=True)

我使用以下代码添加了一个新实例:

tp = TermPayment.objects.create(**kwargs)

我的问题:数据库中的所有记录在日期字段中都有相同的值,即第一次付款的日期。服务器重新启动后,一条记录具有新日期,其他记录与第一条记录相同。好像缓存了一些数据,但是找不到在哪里。

数据库:mysql 5.1.25

django v1.1.1

【问题讨论】:

  • 不可能默认使用这样的函数吗?:default=datetime.now -- 注意,不调用 now() 不是 DateTimeField 的标准,但是......无论如何都很方便。

标签: python django


【解决方案1】:

看起来datetime.now() 在定义模型时被评估,而不是每次添加记录时。

Django 有一个功能可以完成您已经尝试做的事情:

date = models.DateTimeField(auto_now_add=True, blank=True)

date = models.DateTimeField(default=datetime.now, blank=True)

第二个示例与您当前的示例之间的区别在于缺少括号。通过不带括号传递datetime.now,您传递的是实际函数,每次添加记录时都会调用该函数。如果你将它传递给datetime.now(),那么你只是在评估函数并将返回值传递给它。

更多信息请访问 Django 的model field reference

【讨论】:

  • 重要提示:使用 auto_now_add 会使该字段在管理员中不可编辑
  • 很好的答案,谢谢。有没有办法用 datetime.now 作为默认值来表达更复杂的表达式?例如现在 + 30 天(以下不起作用)expiry = models.DateTimeField(default=datetime.now + timedelta(days=30))
  • @michela datetime.now 是一个函数,您正在尝试将 timedelta 添加到函数中。您必须定义自己的回调来设置默认值,例如def now_plus_30(): return datetime.now() + timedelta(days = 30),然后使用models.DateTimeField(default=now_plus_30)
  • 当然也可以default=lambda: datetime.now()+timedelta(days=30)
  • 请注意,使用 auto_now_add NOT 与使用默认值相同,因为该字段将始终等于现在(不可编辑)..我知道这已经说过了,但这不仅仅是“管理”页面的一米
【解决方案2】:

您应该真正使用from django.utils.timezone import now,而不是使用datetime.now

参考:

所以去这样的事情:

from django.utils.timezone import now


created_date = models.DateTimeField(default=now, editable=False)

【讨论】:

  • 这是一个非常重要的注意事项!如果您使用 datetime.now 您可以使用不知道时区的本地日期时间。如果您稍后将其与使用 auto_now_add(可识别时区)时间戳的字段进行比较,您可能会因为错误的时区差异而得到错误的计算。
  • 这绝对是非常重要的,但它本身并不能真正回答问题。
  • 绝对更好的方法
【解决方案3】:

来自 django 模型默认字段上的documentation

字段的默认值。这可以是一个值或可调用对象。如果可调用,则每次创建新对象时都会调用它。

因此以下应该有效:

date = models.DateTimeField(default=datetime.now,blank=True)

【讨论】:

  • 这只能在 django 1.8+ 中实现
  • @DavidNathan 为什么会这样?我认为这两个选项自 1.4 或更早版本就已存在,包括使用可调用 default (django-chinese-docs-14.readthedocs.io/en/latest/ref/models/…)
  • 我收到此错误AttributeError: module 'datetime' has no attribute 'now'。使用default=datetime.datetime.now 修复它
【解决方案4】:

大卫的答案是正确的。括号 () 使得每次评估模型时都会调用 callable timezone.now()。如果您从 timezone.now() 中删除 ()(或 datetime.now(),如果使用天真 datetime 对象)使其成为这样:

default=timezone.now

然后它将按您的预期工作:
新对象在创建时会收到当前日期,但不会在每次执行 manage.py makemigrations/migrate 时都覆盖该日期。

我刚遇到这个。非常感谢大卫。

【讨论】:

    【解决方案5】:

    datetime.now() 在创建类时评估,而不是在将新记录添加到数据库时评估。

    要实现您想要的,请将此字段定义为:

    date = models.DateTimeField(auto_now_add=True)
    

    这样date 字段将被设置为每个新记录的当前日期。

    【讨论】:

      【解决方案6】:

      datetime.now() 被评估一次,当你的类被实例化时。尝试删除括号,以便返回函数 datetime.now 并对其进行评估。我在为DateTimeFields 设置默认值时遇到了同样的问题,并写了我的解决方案here

      【讨论】:

        【解决方案7】:

        来自 Python 语言参考,位于Function definitions

        在执行函数定义时评估默认参数值。这意味着在定义函数时,表达式会被计算一次,并且每次调用都会使用相同的“预计算”值。

        幸运的是,如果您使用 auto_now 参数作为 DateTimeField 的参数,Django 有办法做您想做的事:

        date = models.DateTimeField(auto_now=True)
        

        请参阅DateTimeField 的 Django 文档。

        【讨论】:

          【解决方案8】:

          这个答案其实是错的。

          自动填充值(auto_now/auto_now_add 与默认值不同)。如果它是一个全新的对象,默认值实际上就是用户所看到的。我通常做的是:

          date = models.DateTimeField(default=datetime.now, editable=False,)
          

          如果您尝试在管理页面中表示此内容,请确保将其列为“只读”并引用字段名称

          read_only = 'date'
          

          再次,我这样做是因为我的默认值通常不可编辑,并且除非另有说明,否则管理页面会忽略不可编辑的内容。然而,在设置默认值和实现 auto_add 之间肯定是有区别的,这是这里的关键。测试一下!

          【讨论】:

            【解决方案9】:

            在 Django 3.0 中,auto_now_add 似乎可以与 auto_now 一起使用

            reg_date=models.DateField(auto_now=True,blank=True)

            【讨论】:

              【解决方案10】:

              如果你只需要 DateField 试试这个

              date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
              

              如果你需要日期和时间,试试这个

              date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-12-07
                • 1970-01-01
                • 2016-09-29
                • 2012-11-02
                • 1970-01-01
                • 2010-10-25
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多