如何将Django模型字段的默认值设置为函数调用/可调用(例如,相对于创build模型对象的date)

编辑:

我怎样才能设置一个Django字段的默认值,每次创build一个新的模型对象时得到评估的函数?

我想要做类似于下面的事情,除了在这段代码中,代码被计算一次,并将每个模型对象的默认值设置为相同的date,而不是在每次创build模型对象时评估代码。

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)) 

原版的:

我想创build一个函数参数的默认值,以便它是dynamic的,每次调用函数时都会被调用和设置。 我怎样才能做到这一点? 例如,

 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 

具体来说,我想在Django中做到这一点,例如,

 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)) 

这个问题被误导了。 在Django中创build一个模型字段时,你并没有定义一个函数,所以函数的默认值是不相关的:

 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)) 

最后一行没有定义一个函数。 它正在调用一个函数来在类中创build一个字段。

PRE Django 1.7

Django 允许你传递一个可调用的默认值 ,并且每次都会调用它,就像你想的那样:

 from datetime import datetime, timedelta class MyModel(models.Model): # default to 1 day from now my_date = models.DateTimeField(default=lambda: datetime.now() + timedelta(days=1)) 

Django 1.7+

请注意,从Django 1.7开始,build议不要使用lambda作为默认值(cf @stvnw comment)。 这样做的正确方法是该字段之前声明一个函数并将其用作名为arg的default_value中的可调用对象:

 from datetime import datetime, timedelta # default to 1 day from now def get_default_my_date(): return datetime.now() + timedelta(days=1) class MyModel(models.Model): my_date = models.DateTimeField(default=get_default_my_date) 

下面的@ simanas答案中的更多信息

做这个default=datetime.now()+timedelta(days=1)是绝对错误的!

当你开始你的django的实例时,它会被评估。 如果你是在Apache下,它可能会工作,因为在一些configurationApache的每个请求撤销你的Django的应用程序,但你仍然可以find你自己有一天看你的代码,并试图弄清楚为什么这得到不是你所期望的。

这样做的正确方法是将可调用对象传递给默认参数。 它可以是一个datetime.today函数或您的自定义函数。 然后,每当您请求一个新的默认值时,它都会被评估。

 def get_deadline(): return datetime.today() + timedelta(days=20) class Bill(models.Model): name = models.CharField(max_length=50) customer = models.ForeignKey(User, related_name='bills') date = models.DateField(default=datetime.today) deadline = models.DateField(default=get_deadline) 

以下两个DateTimeField构造函数之间有一个重要的区别:

 my_date = models.DateTimeField(auto_now=True) my_date = models.DateTimeField(auto_now_add=True) 

如果在构造函数中使用auto_now_add=True ,那么my_date引用的date时间是“不可变的”(只有当该行插入到表中时才设置一次)。

但是,使用auto_now=True ,每次保存对象时都会更新date时间值。

这对我来说绝对是一个难题。 作为参考,文档在这里:

https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield

你不能直接这样做; 在评估函数定义时评估默认值。 但是有两种方法。

首先,您可以每次创build(然后调用)一个新函数。

或者,更简单地说,只需使用特殊值来标记默认值。 例如:

 from datetime import datetime def mydate(date=None): if date is None: date = datetime.now() print date 

如果None不是一个完全合理的参数值,并且没有其他合理的值可以使用,那么可以创build一个新的值,这个值绝对在函数的范围之外:

 from datetime import datetime class _MyDateDummyDefault(object): pass def mydate(date=_MyDateDummyDefault): if date is _MyDateDummyDefault: date = datetime.now() print date del _MyDateDummyDefault 

在极less数情况下,你正在编写的元代码确实需要能够完全取代任何东西,比如说, mydate.func_defaults[0] 。 在这种情况下,你必须这样做:

 def mydate(*args, **kw): if 'date' in kw: date = kw['date'] elif len(args): date = args[0] else: date = datetime.now() print date 

作为parameter passing函数而不是传入函数调用的结果。

那就是,而不是这个:

 def myfunc(date=datetime.now()): print date 

尝试这个:

 def myfunc(date=datetime.now): print date()