Django模型字段的默认值可以由依赖于外键父模型的函数定义吗?
我想让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
你最后的例子可能需要一些调整才能正常工作:
- 首先,你需要在你的类里使用
__init__
,而不是models.Model
- 你需要在模型初始化之后再设置你的属性
- 你需要检查模型是否已经保存,否则每次加载模型时,它都会恢复到可覆盖的费用。
-
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()