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
-
是不是可以默认使用这样的函数?:default=datetime.now - 注意,不需要调用now()不是DateTimeField的标准,但是......方便任何。
在定义模型时,似乎正在评估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的模型现场参考
-
重要说明:使用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与使用默认值不同,因为该字段将始终等于现在(不可编辑)..我知道这已经说过了,但它不仅仅是管理页面的一个元素
-
但是如何在上面的示例中将models.DateField设置为当前日期而不是DateTimeField。我尝试过使用date = models.DateField(default = datetime.datetime.now()。date),但它并没有在每天的模型形式Pl中计算到当前日期。指南stackoverflow.com/users/84478/carson-myers
-
@ user956424可能是因为你在定义字段时还在评估now() - 你需要做类似date = models.DateField(default=lambda: datetime.datetime.now().date)的事情
-
它使用上面的stackoverflow.com/users/84478/carson-myers在模型表单中显示
-
@ user956424然后lambda: datetime.datetime.now().date();我不知道now().date是一个功能,抱歉
-
没有什么可抱歉的stackoverflow.com/users/84478/carson-myers你能建议任何其他解决方案吗?
-
这个错误与ValueError: Cannot serialize function: lambda
-
@DavidNathan你在场上设置了serialize=True吗?根据我在源代码中找到的内容,您可以在序列化字段上使用默认函数,但它必须是顶级的,因为它按路径名序序列化:github.com/django/django/blob/master/django/db/车型/场/
-
请注意,将字段与default=datetime.now和auto_now_add混合可能会导致错误,例如计算两者之间的差异 - 因为它们的时区可能不同。最好使用from django.utils.timezone import now而不是datetime.now
而不是使用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) |
-
这是一个非常重要的说明!如果您使用datetime.now,则可以使用不知道时区的本地日期时间。如果您稍后将其与使用auto_now_add(可识别时区)时间戳的字段进行比较,则由于时区差异,您可能会得到错误的计算结果。
-
这绝对是非常重要的,但它本身并没有真正回答这个问题。
-
明确更好的方式
从django模型默认字段的文档:
字段的默认值。这可以是值或可调用对象。如果可调用,则每次创建新对象时都会调用它。
因此以下应该工作:
1
| 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/)
大卫有正确的答案。括号()使得每次评估模型时都会调用可调用的timezone.now()。如果你从timezone.now()(或datetime.now(),如果使用天真的datetime对象)删除(),使它只是这样:
然后它将按预期工作:
新对象将在创建时收到当前日期,但每次执行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"并引用字段名称
同样,我这样做是因为我的默认值通常不可编辑,管理页面会忽略不可编辑的内容,除非另有说明。然而,在设置默认值和实现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文档。