EDITED:
How can I set a Django field's default to a function that gets evaluated each time a new model object gets created?
I want to do something like the following, except that in this code, the code gets evaluated once and sets the default to the same date for each model object created, rather than evaluating the code each time a model object gets created:
from datetime import datetime, timedelta
class MyModel(models.Model):
# default to 1 day from now
my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))
ORIGINAL:
I want to create a default value for a function parameter such that it is dynamic and gets called and set each time the function is called. How can I do that? e.g.,
from datetime import datetime
def mydate(date=datetime.now()):
print date
mydate()
mydate() # prints the same thing as the previous call; but I want it to be a newer value
Specifically, I want to do it in Django, e.g.,
from datetime import datetime, timedelta
class MyModel(models.Model):
# default to 1 day from now
my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))
You can't do that directly; the default value is evaluated when the function definition is evaluated. But there are two ways around it.
First, you can create (and then call) a new function each time.
Or, more simply, just use a special value to mark the default. For example:
If
None
is a perfectly reasonable parameter value, and there's no other reasonable value you could use in its place, you can just create a new value that's definitely outside the domain of your function:In some rare cases, you're writing meta-code that really does need to be able to take absolutely anything, even, say,
mydate.func_defaults[0]
. In that case, you have to do something like this:Sometimes you may need to access model data after creating a new user model.
Here is how I generate a token for each new user profile using the first 4 characters of their username:
The question is misguided. When creating a model field in Django, you are not defining a function, so function default values are irrelevant:
This last line is not defining a function; it is invoking a function to create a field in the class.
PRE Django 1.7
Django lets you pass a callable as the default, and it will invoke it each time, just as you want:
Django 1.7+
Please note that since Django 1.7, usage of lambda as default value is not recommended (c.f. @stvnw comment). The proper way to do this is to declare a function before the field and use it as a callable in default_value named arg:
More information in the @simanas answer below
There's an important distinction between the following two DateTimeField constructors:
If you use
auto_now_add=True
in the constructor, the datetime referenced by my_date is "immutable" (only set once when the row is inserted to the table).With
auto_now=True
, however, the datetime value will be updated every time the object is saved.This was definitely a gotcha for me at one point. For reference, the docs are here:
https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield
Pass the function in as a parameter instead of passing in the result of the function call.
That is, instead of this:
Try this:
Doing this
default=datetime.now()+timedelta(days=1)
is absolutely wrong!It gets evaluated when you start your instance of django. If you are under apache it will probably work, because on some configurations apache revokes your django application on every request, but still you can find you self some day looking through out your code and trying to figure out why this get calculated not as you expect.
The right way of doing this is to pass a callable object to default argument. It can be a datetime.today function or your custom function. Then it gets evaluated every time you request a new default value.