Odoo中无法存储计算字段时,如何按月追踪对比计算字段值?
嘿,针对你遇到的这个计算字段历史值追踪的问题,我整理了几个实用的方案,你可以根据自己的需求来选~
可行的替代方案来追踪计算字段的历史值
1. 新建历史快照表(首推方案)
专门建一个模型来存储每个时间节点的计算字段快照,这样你能精准保留每月1号的b值,后续对比差异直接查这个表就行,逻辑清晰还容易维护。
具体实现步骤:
首先定义历史快照模型:
class ModelAHistory(models.Model): _name = 'model.a.history' _description = 'Model A Monthly Value Snapshot' model_a_id = fields.Many2one('model.a', string='Model A Record', required=True) snapshot_date = fields.Date(string='Snapshot Date', required=True) b_value = fields.Float(string='Calculated B Value', required=True)
然后写个方法来计算并存储当月的快照:
def _create_monthly_snapshot(self): today = fields.Date.today() # 取当月1号作为快照日期,你也可以根据需求调整成其他固定日期 snapshot_date = today.replace(day=1) # 遍历所有Model A记录,计算当前b值并存入历史表 for record in self.env['model.a'].search([]): # 手动触发计算(如果b没设置存储的话) record._compute_field() self.env['model.a.history'].create({ 'model_a_id': record.id, 'snapshot_date': snapshot_date, 'b_value': record.b })
最后在Odoo的后台配置一个每月1号执行的定时任务,调用上面的方法,就能自动生成当月的快照了。
之后要对比的时候,直接查历史表就行,比如拿4月和5月的数据对比:
april_snapshots = self.env['model.a.history'].search([('snapshot_date', '=', '2018-04-01')]) may_snapshots = self.env['model.a.history'].search([('snapshot_date', '=', '2018-05-01')]) for april, may in zip(april_snapshots, may_snapshots): difference = may.b_value - april.b_value # 这里写你处理差异的逻辑,比如打印、生成报表之类的
2. 先排查store=True失效的问题(如果想直接存储计算字段)
你说设置store=True后b一直显示0,大概率是计算方法的依赖声明或者逻辑出了问题,先试试排查这个:
- 一定要给计算方法加上
@api.depends装饰器,明确声明依赖的c和d字段,不然Odoo不知道什么时候触发计算:
from odoo import api, fields, models class ModelA(models.Model): _name = 'model.a' c = fields.Float() d = fields.Float() b = fields.Float(compute='_compute_field', store=True) @api.depends('c', 'd') def _compute_field(self): for record in self: # 替换成你实际的计算逻辑 record.b = record.c + record.d
- 如果
c或d是关联字段(比如partner_id.amount),要把完整的依赖路径写在depends里,比如@api.depends('partner_id.amount')。 - 还要检查有没有其他继承的模型或者逻辑不小心覆盖了
b的计算值。
不过要注意:就算store=True生效了,b字段存的是当前最新值,不会保留历史版本。如果要对比不同日期的数值,还是得结合上面的历史快照表,或者用Odoo的审计日志查变更记录,但审计日志更适合追踪变更时间点,不是固定日期的快照。
3. 临时计算+报表查询(适合一次性对比需求)
如果只是偶尔需要生成对比报表,不需要长期存历史值,可以试试动态计算指定日期的b值:
- 前提是
c和d的历史值能被追溯,比如你给这两个字段开了track_visibility,或者有专门的表存它们的变更记录。 - 写个方法,传入目标日期,找到该日期时
c和d的值,再计算对应的b,然后和其他日期的结果对比。
这个方案适合临时需求,但长期用的话还是快照表更靠谱。
内容的提问来源于stack exchange,提问作者fueggit
相关产品推荐
相关产品推荐

