ChatGPT解决这个技术问题 Extra ChatGPT

Django 日期时间问题(默认=datetime.now())

我有以下数据库模型:

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 的标准,但是......无论如何都很方便。

C
Carson Myers

似乎在定义模型时正在评估 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 与使用默认值不同,因为该字段将始终等于现在(不可编辑)。我知道这已经说过,但这不仅仅是“管理”页面的一米
a
andilabs

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

参考:

django.utils.timezone.now 的文档

所以去做这样的事情:

from django.utils.timezone import now


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

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

从 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 修复它
M
MicahT

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

default=timezone.now

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

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


B
Bartosz

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

为了实现你想要的定义这个字段:

date = models.DateTimeField(auto_now_add=True)

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


v
vishes_shell

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


a
ars

在 Python 语言参考的 Function definitions 下:

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

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

date = models.DateTimeField(auto_now=True)

请参阅 DateTimeField 的 Django 文档。


A
Andrew Harris

这个问题的答案实际上是错误的。

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

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

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

read_only = 'date'

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


M
Mayur Dhurpate

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

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


S
Sven Eberth

如果你只需要 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)