我准备基于现有字段值进行一些简单的数学运算,并将其存储在当前实例的单独字段(小计)中。
我的问题实际上已包含在最后一段代码中。
class Element(models.Model):
name = models.CharField(max_length=128)
kids = models.ManyToManyField('self', null=True, blank=True, symmetrical=False)
price = models.IntegerField('unit price', null=True, blank=True)
amount = models.IntegerField('amount', null=True, blank=True)
subtotal = models.IntegerField(null=True, blank=True)
def counter(self):
output = 0
# Check if this is the lowest hierarchy level (where the intention is to
# store both values for price and amount) and proceed calculations
# based on input values. Also check if values are set to avoid operations
# with incompatible types.
# Else aggregate Sum() on subtotal values of all kids.
if self.kids.count() == 0:
if self.price == None or self.amount == None:
output = 0
else:
output = self.price * self.amount
else:
output = self.kids.aggregate(Sum('subtotal'))['subtotal__sum']
self.subtotal = output
def __unicode__(self):
return self.name
这就是我的样本数据的样子(如果我错过了一些如何展示它的惯例,我很抱歉。)
element.name = son
element.kids = # None
element.price = 100
element.amount = 1
element.subtotal = 100 # Calculates and stores correct value.
element.name = daughter
element.kids = # None
element.price = 200
element.amount = 5
element.subtotal = 1000 # Calculates and stores correct value.
element.name = father
element.kids = son, daughter
element.price = # None. Use this field for overriding the calculated
# price at this level.
element.amount = # None.
element.subtotal = 25 # Calculates completely irrelevant value.
# The result seems to be some previous state
# (first maybe) of subtotal of one of the kids.
# This is where my cache part of question comes from.
在解决这个简单的任务时,我已经开始使用clean()类,但结果是在第二次保存之后计算的(可能是另一个问题的好主题)。我切换到自定义方法。但是现在经过一个晚上的花费,我会很自豪地使用Owl先生对小熊维尼的话:“你先生卡住了!”此时我只使用原生的django管理表单。任何帮助都将非常感激。
答案 0 :(得分:0)
如果没有看到您用来调用所有这些计算的代码,我只能猜出问题可能是什么。显示您的视图代码(或其他)可能会有所帮助,它会“开始”小计的计算。
我可以在这里看到两个潜在的问题。
第一种是你的反方法。您是在计算总数后保存模型实例吗?
def counter(self):
output = 0
if self.kids.count() == 0:
if self.price == None or self.amount == None:
output = 0
else:
output = self.price * self.amount
else:
output = self.kids.aggregate(Sum('subtotal'))['subtotal__sum']
self.subtotal = output
self.save() # save the calculation
如果不保存实例,当您从父级查询子级时,将获得当前数据库值而不是新计算的值。这可能是也可能不是问题,具体取决于开始调用counter
的代码。
我在这里看到的另一个潜在问题是缓存失效。如果孩子更新了他们的price
或amount
,是否已通知家长,以便其也可以更新其subtotal
?您可以在最后一刻覆盖save
方法进行计算。
def save(self, *args, **kwargs):
self.counter() # calculate subtotal
super(Element, self).save(*args, **kwargs) # Call the "real" save() method.
for parent in self.element_set.all(): # use a related name instead
parent.save() # force recalculation of each parent
您会注意到这只会在仅保存后强制正确的小计值有效。请注意,以这种方式覆盖save方法与我在计算计数器时保存实例的第一个解决方案完全矛盾。如果你同时使用两者,你将获得一个StackOverflow,因为计算器然后被保存,然后在计算保存计数器期间,这将触发另一次保存。坏消息。