Reputation: 4937
I am in the process of upgrading my project from Django 1.8.2 to 1.9.7 and I'm getting this warning:
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
Here's the line from my_app/models.py:
from django.utils import timezone
...
class my_model(models.Model):
...
datetime_released = models.DateTimeField(default=timezone.now() )
If I remove the parentheses and instead use:
datetime_released = models.DateTimeField(default=timezone.now )
The Django warning goes away. What's the difference between the two?
In another area of my project I am using timezone.now() in a queryset filter:
def date_available(self):
return self.filter(date_available__lte = timezone.now())
Here, if I remove the parentheses, an error is thrown:
TypeError: expected string or buffer
I can get both of these two work by adding/removing the parenthesis as required, but what is the difference between timezone.now()
and timezone.now
and why do they cause warnings/errors in these cases?
Upvotes: 33
Views: 29076
Reputation: 11
timezone.now() returns the current timestamp when when model is loaded. On the other hand, timezone.now is passed as an argument to the function and it is called whenever the object is created (on class instantiation)
in the following code
def date_available(self):
return self.filter(date_available__lte = timezone.now())
the function date_availabe needs a function string to parse as a function when it returns self.filter.
Upvotes: 1
Reputation: 34972
In python everything is an object, including functions. This means you can affect a function to a variable:
>>> from django.utils import timezone
>>> foo = timezone.now
>>> foo
<function django.utils.timezone.now>
>>> foo()
datetime.datetime(2016, 7, 7, 9, 11, 6, 489063)
A function is a callable object:
>>> callable(foo)
True
>>> callable(foo())
False
When default
receives a callable, the callable is called each time a default value is requested.
On the other hand, when you call timezone.now()
prior to setting default
, the value is given and fixed. As a reminder, the following line is executed only once at server start up, since it is a class attribute:
datetime_released = models.DateTimeField(default=timezone.now())
and thus timezone.now()
is executed only once. Passing a callable timezone.now
makes it possible to recalculate the value whenever it needs to be.
Upvotes: 48
Reputation: 4689
now() gets executed when the model is loaded and returns a datetime object / time string at loading. (hence the Django warning!) (The model file if fully executed when the server starts)
now will pass on the now method, and will get executed only when the class/model gets instantiated, creating the time stamp at the right time (the correct way, and what most people are trying to achieve).
In the filter example, it only gets called when the filter function is called. if you don't executed (now()) and will feed the method, and will never generate the required datetime object. (error, expected a string, got, something else)
Upvotes: 1
Reputation: 7734
In self.filter(date_available__lte = timezone.now())
you want to make a query to the DB based on the current time. So you need it in string format.
In datetime_released = models.DateTimeField(default=timezone.now)
you want default to be current time. So you cannot have a string there. Instead you provide a function which can return current time.
Upvotes: 2
Reputation: 31424
The difference is that timezone.now
is a callable that gets executed at runtime, while timezone.now()
returns the output of that function.
For the models.DateTimeField
, you need to use the callable. Better still, just set auto_now_add
which does this for you:
datetime_released = models.DateTimeField(auto_now_add=True)
The filter on the other hand does not accept a callable - it requires a value. Hence you must evaluate timezone.now()
when passing this as an argument to the filter.
Upvotes: 12