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

Sha*_*nu4 256 python django

我有这样的db模型:

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)
Run Code Online (Sandbox Code Playgroud)

当添加新实例时:

tp = TermPayment.objects.create(**kwargs)
Run Code Online (Sandbox Code Playgroud)

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

数据库:mysql 5.1.25

django v1.1.1

Car*_*ers 549

它看起来像是datetime.now()在定义模型时进行评估,而不是每次添加记录时都要进行评估.

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

date = models.DateTimeField(auto_now_add=True, blank=True)
Run Code Online (Sandbox Code Playgroud)

要么

date = models.DateTimeField(default=datetime.now, blank=True)
Run Code Online (Sandbox Code Playgroud)

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

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

  • **重要说明**:使用auto_now_add会在admin中呈现不可编辑的字段 (192认同)
  • 或者你当然可以做`default = lambda:datetime.now()+ timedelta(days = 30)` (53认同)
  • **请注意**使用auto_now_add******与使用默认值相同,因为该字段总是等于现在(不可编辑)..我知道这已经说过,但它不仅仅是一个'管理员'页面 (33认同)
  • @michela datetime.now是一个函数,您正在尝试向函数添加timedelta.你必须定义自己的回调来设置默认值,比如`def now_plus_30():return datetime.now()+ timedelta(days = 30)`,然后使用`models.DateTimeField(default = now_plus_30)` (22认同)
  • 很好的回答,谢谢.有没有办法用datetime.now表达更复杂的表达式作为默认值?例如现在+ 30天(以下不起作用)`expiry = models.DateTimeField(default = datetime.now + timedelta(days = 30))` (7认同)
  • 请注意,将字段与`default = datetime.now`和`auto_now_add`混合可能会导致错误,例如计算两者之间的差异 - 因为它们的时区可能不同.最好使用`from django.utils.timezone import now`而不是`datetime.now` (2认同)

and*_*abs 91

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

参考:

所以去这样的事情:

from django.utils.timezone import now


created_date = models.DateTimeField(default=now, editable=False)
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常重要的说明!如果您使用datetime.now,则可以使用不符合时区的本地日期时间.如果您稍后将其与使用"auto_now_add"(可识别时区)的时间戳进行比较,则由于时区差异,您可能会得到错误的计算结果. (10认同)
  • 这绝对非常重要,但其本身并不能真正回答问题。 (2认同)

myk*_*hal 26

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

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

因此以下应该工作:

date = models.DateTimeField(default=datetime.now,blank=True)
Run Code Online (Sandbox Code Playgroud)


小智 16

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

default=timezone.now
Run Code Online (Sandbox Code Playgroud)

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

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


Bar*_*osz 9

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

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

date = models.DateTimeField(auto_now_add=True)
Run Code Online (Sandbox Code Playgroud)

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


Dav*_*vid 6

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


And*_*ris 6

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

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

date = models.DateTimeField(default=datetime.now, editable=False,)
Run Code Online (Sandbox Code Playgroud)

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

read_only = 'date'
Run Code Online (Sandbox Code Playgroud)

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


ars*_*ars 5

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

执行函数定义时,将评估默认参数值.这意味着当定义函数时,表达式被计算一次,并且每个调用使用相同的"预先计算"值.

幸运的是,Django有一种方法可以做你想要的,如果你使用auto_now参数DateTimeField:

date = models.DateTimeField(auto_now=True)
Run Code Online (Sandbox Code Playgroud)

请参阅DateTimeField的Django文档.