Django模型:设置相对于另一个字段的默认值

11

我正在使用Django 1.10作为后端构建应用程序。是否可以将模型字段的默认值相对于同一实例中的另一个模型进行设置?

我特别需要将second_visit的默认值设置为在first_visit之后3周。

class SomeModel(models.Model): 
    first_visit = models.DateField()
    second_visit = models.DateField(default= second_visit_default)

    def second_visit_default(self):
        # Set second_visit to 3 weeks after first_visit
3个回答

12

在创建模型实例之前,您无法为依赖于另一个字段的字段分配默认值。要实现相同的功能,可以重写模型的save()方法:

class SomeModel(models.Model):

    ...

    def save(self, *args, **kwargs):
        self.second_visit = self.first_visit + datetime.timedelta(weeks=3)
        super().save(*args, **kwargs)

5
警告:这与设置默认值不同。这将导致模型的任何后续保存都会出现问题,因为用户实际上希望在该字段中设置显式值。 - BjornW

2
您可以重写save或使用pre_save
from django.db.models.signals import pre_save
from django.dispatch import receiver


@receiver(pre_save, sender=SomeModel)
def my_handler(sender, instance, **kwargs):
    instance.second_visit = # Set second_visit to 3 weeks after instance.first_visit

1

这是一个晚回答,但@BjornW被接受的答案评论中提出了一个有效的问题,这个问题在 2 个已有答案(在写作时)中并没有解决:覆盖 save 并不等同于设置默认值;默认值只会在第一次实例创建时生效,而修改 save 则会影响每次现有实例修改。第二个答案也存在与默认值原则的偏差。

尽管无法相对于 self 的其他属性提供默认值,但是可以使用 pre_save 信号来设置相对于其他字段的默认值。

下面是一个示例:

# signals.py
from django.dispatch import receiver
from django.db.models.signals import pre_save
# do all necessary imports e.g.:
from .models import SomeModel

@receiver(pre_save, sender=SomeModel)
def set_default_second_visit(sender, instance, raw, **kwargs):
    """
    Set default value for `second_visit`
    """
    if instance.pk is None:
        instance.second_visit = instance.second_visit or instance.first_visit + datetime.timedelta(weeks=3)

可能需要注意的一点:

pre_save信号不仅会在保存新实例时发送,实际上每当保存SomeModel的实例时都会发送,即使修改了来自数据库的现有条目也是如此。 if instance.pk is None:这行代码的存在和必要性正是出于这个原因:它确保只有在对象尚不存在于数据库中(即尚未具有主键)时才设置该值。


问题是,批量方法(例如bulk_create()bulk_update())不会发送pre_save信号或调用.save() 方法,使得这种解决方案不足够:( - Gabriel Tkacz

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