优先考虑相互依赖的计算字段
Prioritizing calculated fields that depend on each other
在我的 odoo 实例中,我在分析帐户上有几个计算字段 object。这些字段经过计算以确保查看者始终拥有最新的概览。
其中一些字段依赖于其他字段,这些字段本身就是计算字段。计算本身相当简单(字段 A = 字段 B + 字段 C)。大多数字段还取决于基础 child id。例如,顶部object 的字段A 是child id 的所有字段A 值的汇总。 children上的字段A是根据自己的字段B和C合并计算的,如上所述。
我目前所处的情况是,由于某种原因,这些字段似乎是按随机顺序计算的。我注意到这一点是因为当我快速连续刷新时,同一条记录会得到不同的值。
示例:
字段 B 和 C 都是 10。我希望 A 为 20 (B+C),但大多数时候它实际上是 0,因为 A 的字段计算发生在 B 和 C 之前。有时它是 10,因为 B 或 C 在 A 之前偷偷进入可以完成。在极少数情况下,它实际上是 20....
注意:
- 我无法存储这些字段,因为它们将取决于以令人难以置信的速度创建的帐户移动行,并且数据库将绝对疯狂地每分钟左右重新计算所有记录。
- 我已经添加了 @api.depends 但这仅在您使用存储字段确定字段应触发它时才有用,这不适用于我的情况。
有谁知道解决这个问题的方法吗?或者对其他计算方法有什么建议?
[编辑] 添加代码
示例代码:
@api.multi
@api.depends('child_ids','costs_allowed','total_cost')
def _compute_production_result(self):
for rec in self:
rec_prod_cost = 0.0
if rec.usage_type in ['contract','project']:
for child in rec.child_ids:
rec_prod_cost += child.production_result
elif rec.usage_type in ['cost_control','planning']:
rec_prod_cost = rec.costs_allowed - rec.total_cost
rec.production_result = rec_prod_cost
如您所见,如果我们在合同或项目中,我们需要查看 children(cost_control 帐户)的结果并将它们加在一起。如果我们实际上是在 cost_control 帐户上,那么我们可以通过获取字段 B 和 C 并(在本例中)减去它们来获得实际值。
如果在 cost_control 之前处理合同记录,或者在评估 cost_control 帐户时 costs_allowed 和 total_cost 字段为 0.0,就会出现问题。
请注意:costs_allowed 和 total_cost 都是计算字段,就其本身而言!
您可能会发现 python @properties
有帮助。不仅仅是使用普通字段,这允许您定义一些看起来像字段的东西,但是是惰性评估的 - 即当您 'get' 它时按需计算。这样我们可以保证它是最新的。一个例子:
import datetime
class Person(object):
def __init__(self):
self._born = datetime.datetime.now()
@property
def age(self):
return datetime.datetime.now() - self._born
p = Person()
# do some stuff...
# We can 'get' age just like a field, but it is lazy evaluated
# i.e. calculated on demand
# This way we can guarantee it's up to date
print(p.age)
您可以像他们在 Invoice 中那样做,许多计算字段依赖于许多其他字段,并且它们为每个计算字段设置一个值。
@api.one
@api.depends('X', 'Y', ...)
def _compute_amounts(self):
self.A = ...
self.B = ...
self.C = self.A + self.B
所以我设法找到了一位同事,我们一起解决了这个问题。
事实证明,当您定义一个方法来计算它自己的记录以及依赖于子记录上的该字段的字段时,您需要在依赖项中明确提及这一点。
例如:
@api.multi
@api.depends('a', 'b', 'c')
def _compute_a(self):
for rec in self:
if condition:
rec.a = sum(child_ids.a)
else:
rec.a = rec.b + rec.c
在此示例中,self 对象包含记录 (1,2,3,4)。
如果您包含依赖项但让代码保持不变,就像这样:
@api.multi
@api.depends('a', 'b', 'c', 'child_ids.a')
def _compute_a(self):
for rec in self:
if condition:
rec.a = sum(child_ids.a)
else:
rec.a = rec.b + rec.c
将运行此方法4次,从lowest/deepest候选人开始。所以 self 在这种情况下将是 (4),然后是 (3),等等
太糟糕了,这个逻辑似乎是隐含的,并没有在任何地方真正描述(据我所知)。
在我的 odoo 实例中,我在分析帐户上有几个计算字段 object。这些字段经过计算以确保查看者始终拥有最新的概览。
其中一些字段依赖于其他字段,这些字段本身就是计算字段。计算本身相当简单(字段 A = 字段 B + 字段 C)。大多数字段还取决于基础 child id。例如,顶部object 的字段A 是child id 的所有字段A 值的汇总。 children上的字段A是根据自己的字段B和C合并计算的,如上所述。
我目前所处的情况是,由于某种原因,这些字段似乎是按随机顺序计算的。我注意到这一点是因为当我快速连续刷新时,同一条记录会得到不同的值。
示例: 字段 B 和 C 都是 10。我希望 A 为 20 (B+C),但大多数时候它实际上是 0,因为 A 的字段计算发生在 B 和 C 之前。有时它是 10,因为 B 或 C 在 A 之前偷偷进入可以完成。在极少数情况下,它实际上是 20....
注意: - 我无法存储这些字段,因为它们将取决于以令人难以置信的速度创建的帐户移动行,并且数据库将绝对疯狂地每分钟左右重新计算所有记录。 - 我已经添加了 @api.depends 但这仅在您使用存储字段确定字段应触发它时才有用,这不适用于我的情况。
有谁知道解决这个问题的方法吗?或者对其他计算方法有什么建议?
[编辑] 添加代码
示例代码:
@api.multi
@api.depends('child_ids','costs_allowed','total_cost')
def _compute_production_result(self):
for rec in self:
rec_prod_cost = 0.0
if rec.usage_type in ['contract','project']:
for child in rec.child_ids:
rec_prod_cost += child.production_result
elif rec.usage_type in ['cost_control','planning']:
rec_prod_cost = rec.costs_allowed - rec.total_cost
rec.production_result = rec_prod_cost
如您所见,如果我们在合同或项目中,我们需要查看 children(cost_control 帐户)的结果并将它们加在一起。如果我们实际上是在 cost_control 帐户上,那么我们可以通过获取字段 B 和 C 并(在本例中)减去它们来获得实际值。
如果在 cost_control 之前处理合同记录,或者在评估 cost_control 帐户时 costs_allowed 和 total_cost 字段为 0.0,就会出现问题。
请注意:costs_allowed 和 total_cost 都是计算字段,就其本身而言!
您可能会发现 python @properties
有帮助。不仅仅是使用普通字段,这允许您定义一些看起来像字段的东西,但是是惰性评估的 - 即当您 'get' 它时按需计算。这样我们可以保证它是最新的。一个例子:
import datetime
class Person(object):
def __init__(self):
self._born = datetime.datetime.now()
@property
def age(self):
return datetime.datetime.now() - self._born
p = Person()
# do some stuff...
# We can 'get' age just like a field, but it is lazy evaluated
# i.e. calculated on demand
# This way we can guarantee it's up to date
print(p.age)
您可以像他们在 Invoice 中那样做,许多计算字段依赖于许多其他字段,并且它们为每个计算字段设置一个值。
@api.one
@api.depends('X', 'Y', ...)
def _compute_amounts(self):
self.A = ...
self.B = ...
self.C = self.A + self.B
所以我设法找到了一位同事,我们一起解决了这个问题。 事实证明,当您定义一个方法来计算它自己的记录以及依赖于子记录上的该字段的字段时,您需要在依赖项中明确提及这一点。
例如:
@api.multi
@api.depends('a', 'b', 'c')
def _compute_a(self):
for rec in self:
if condition:
rec.a = sum(child_ids.a)
else:
rec.a = rec.b + rec.c
在此示例中,self 对象包含记录 (1,2,3,4)。 如果您包含依赖项但让代码保持不变,就像这样:
@api.multi
@api.depends('a', 'b', 'c', 'child_ids.a')
def _compute_a(self):
for rec in self:
if condition:
rec.a = sum(child_ids.a)
else:
rec.a = rec.b + rec.c
将运行此方法4次,从lowest/deepest候选人开始。所以 self 在这种情况下将是 (4),然后是 (3),等等
太糟糕了,这个逻辑似乎是隐含的,并没有在任何地方真正描述(据我所知)。