关于python:Django日期时间问题(默认= datetime.now())

Django datetime issues (default=datetime.now())

我有以下数据库模型:

1
2
3
4
5
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)

我使用下面的方法添加一个新实例:

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

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

数据库:mysql 5.1.25

django v1.1.1


在定义模型时,似乎正在评估datetime.now(),而不是每次添加记录时都评估datetime.now()

Django有一个功能来完成你想要做的事情:

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

要么

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

第二个例子与你现在拥有的不同之处在于缺少括号。通过传递datetime.now而没有括号,您将传递实际函数,每次添加记录时都会调用该函数。如果你传递它datetime.now(),那么你只是评估函数并传递返回值。

有关更多信息,请参阅Django的模型现场参考


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

参考:

  • django.utils.timezone.now的文档

所以去这样的事情:

1
2
3
4
from django.utils.timezone import now


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


从django模型默认字段的文档:

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

因此以下应该工作:

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


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

1
default=timezone.now

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

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


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

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

1
date = models.DateTimeField(auto_now_add=True)

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


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

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

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

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

1
read_only = 'date'

同样,我这样做是因为我的默认值通常不可编辑,管理页面会忽略不可编辑的内容,除非另有说明。然而,在设置默认值和实现auto_add之间肯定存在差异,这是关键。测试出来!


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


从Python语言参考,在函数定义下:

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that that same"pre-computed" value is used for each call.

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

1
date = models.DateTimeField(auto_now=True)

请参阅DateTimeField的Django文档。