Django模型字段的默认值可以由依赖于外键父模型的函数定义吗?

8 投票
1 回答
7118 浏览
提问于 2025-04-17 04:56

我想让Report的费用默认值根据父模型的属性来设置。我不想在save()方法里处理这个,因为如果用户想在保存之前修改这个值,这个字段需要展示给他们。

我尝试了三种方法,除了只传递函数指针(也就是不加())。当我运行python manage.py shell时,出现了错误。

#1
from django.db import models

class Job(models.Model):
    veryImportant = models.IntegerField()
    def get_fee(self):
        return 2 * self.veryImportant

class Report(models.Model):
    job = models.ForeignKey(Job)
    overridableFee = models.DecimalField(default=job.get_fee(), max_digits=7, decimal_places=2)

#gives...
#AttributeError: 'ForeignKey' object has no attribute 'get_fee'

#2
from django.db import models

class Job(models.Model):
    veryImportant = models.IntegerField()

class Report(models.Model):
    job = models.ForeignKey(Job)
    overridableFee = models.DecimalField(default=self.set_fee(), max_digits=7, decimal_places=2)
    def set_fee(self):
        overridableFee =  2 * self.job.veryImportant

#gives...
#NameError: name 'self' is not defined

#3
from django.db import models

class Job(models.Model):
    veryImportant = models.IntegerField()
    def get_fee():
        return 2 * veryImportant

class Report(models.Model):
    job = models.ForeignKey(Job)
    overridableFee = models.DecimalField(max_digits=7, decimal_places=2)
    def __init__(self, *args, **kwargs):
        self.overridableFee = self.job.get_fee()
        super(models.Model, self).__init__(*args, **kwargs)

#gives...
#TypeError: object.__init__() takes no parameters

第三种方法出错的原因可能是我根本不知道怎么正确地重写init。我从其他答案里复制了一些东西,但在它不工作后就放弃了。

如果这些方法都不行,我可以在视图中创建每个Report后再设置费用,但我更希望在Report创建时自动设置,这样更方便。

编辑:

最后我选择了第三种方法,按照Yuji的答案进行了修正,并修改了代码以确保从shell设置的任何费用都能覆盖job.get_fee()想要的值。

def __init__(self, *args, **kwargs):
    super(Report, self).__init__(*args, **kwargs)
    if self.overridableFee == None and self.job and not self.pk:
        self.overridableFee = self.job.get_fee()

1 个回答

8

你最后的例子可能需要一些调整才能正常工作:

  1. 首先,你需要在你的类里使用 __init__,而不是 models.Model
  2. 你需要在模型初始化之后再设置你的属性
  3. 你需要检查模型是否已经保存,否则每次加载模型时,它都会恢复到可覆盖的费用。

-

class Job(models.Model):
    veryImportant = models.IntegerField()
    def get_fee():
        return 2 * veryImportant

class Report(models.Model):
    job = models.ForeignKey(Job)
    overridableFee = models.DecimalField(max_digits=7, decimal_places=2)
    def __init__(self, *args, **kwargs):
        super(Report, self).__init__(*args, **kwargs)
        if not self.id:
            self.overridableFee = self.job.get_fee() 

撰写回答