Django: timezone.now与timezone.now()的区别

33

我正在将我的项目从Django 1.8.2升级到1.9.7的过程中,但是我遇到了这个警告:

WARNINGS:
my_app.my_model.date_available: (fields.W161) Fixed default value provided.
HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. 
If you want to have the current date as default, use `django.utils.timezone.now

这是来自于my_app/models.py文件的代码行:

from django.utils import timezone
...
class my_model(models.Model):
    ...
    datetime_released = models.DateTimeField(default=timezone.now() )

如果我去掉括号,改用:

datetime_released = models.DateTimeField(default=timezone.now )

Django的警告已经消失了。这两者之间有什么区别?


在我项目的另一个区域,我正在使用timezone.now()在查询集过滤器中:

def date_available(self):
        return self.filter(date_available__lte = timezone.now())

如果我去掉括号,会出现错误:

TypeError: 预期字符串或缓冲区


根据需要添加/删除括号可以使这两个工作正常,但timezone.now()timezone.now之间有什么区别,并且为什么它们在这些情况下会导致警告或错误?


type(now()) 返回一个日期时间对象。type(now) 返回方法 now。 - gtalarico
5个回答

48

在Python中,一切都是对象,包括函数。这意味着您可以将函数赋值给变量:

>>> from django.utils import timezone
>>> foo = timezone.now
>>> foo
<function django.utils.timezone.now>
>>> foo()
datetime.datetime(2016, 7, 7, 9, 11, 6, 489063)

函数是一个可调用的对象:

>>> callable(foo)
True
>>> callable(foo())
False

default 收到可调用对象时,每次请求默认值时都会调用该可调用对象。

另一方面,如果在设置 default 之前调用了 timezone.now(),则该值会被给出并固定。请注意,以下行只在服务器启动时执行一次,因为它是一个类属性:

    datetime_released = models.DateTimeField(default=timezone.now())

因此timezone.now()仅被执行一次。传递可调用对象timezone.now可以在需要时重新计算值。


我还是不明白。timezone.now() 还能正常工作吗,还是只需要使用 timezone.now - AnonymousUser
1
这取决于你对“工作”的定义。使用models.DateTimeField(default=timezone.now())会“工作”,但是你将默认值设置为服务器启动的时间。 - Antoine Pinsard
所以 timezone.now 在创建模型时会更新为今天,之后不会再更新了吗? - AnonymousUser

12

区别在于timezone.now是一个在运行时执行的可调用函数,而timezone.now()返回该函数的输出。

对于models.DateTimeField,您需要使用可调用函数。更好的选择是,只需设置auto_now_add即可为您完成此操作:

datetime_released = models.DateTimeField(auto_now_add=True)

然而,筛选器不接受可调用对象 - 它需要一个数值。因此,在将其作为筛选器参数传递时,您必须评估timezone.now()


这里值得一提的是,当你传递 timezone.now() 时,实际上是在 django 启动时(即被评估时)传递该函数的输出,而当你传递 timezone.now 时,你传递的是由 django 惰性评估的函数对象。 - samu
如果您想要一个具有创建时间戳的模型,那么timezone.now()是否比timezone.now更好,因为后者会被重新评估。 - Dorian Dore

2
self.filter(date_available__lte = timezone.now()) 中,您想要根据当前时间向数据库进行查询。因此,您需要将其转换为字符串格式。
datetime_released = models.DateTimeField(default=timezone.now) 中,您希望默认值为当前时间。因此,您不能在那里放置一个字符串。相反,您提供一个可以返回当前时间的函数。

1

now()会在模型加载时执行并返回一个日期时间对象/时间字符串。(因此Django会发出警告!) (模型文件完全在服务器启动时执行)

now将传递now方法,并仅在类/模型被实例化时执行,以在正确的时间创建时间戳(这是正确的方式,也是大多数人想要实现的)。

在过滤器示例中,它仅在调用过滤器函数时才被调用。 如果您不执行(now())并提供该方法,则永远不会生成所需的日期时间对象。(错误,期望字符串,得到其他内容)


1

timezone.now()返回模型加载时的当前时间戳。另一方面,timezone.now作为参数传递给函数,并且每当对象被创建(在类实例化时)时调用它。

在以下代码中

def date_available(self):
    return self.filter(date_available__lte = timezone.now())

函数date_available需要一个字符串函数来解析为一个函数,当它返回self.filter时。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接