Odoo 12中many2many字段track_visibility不支持及失效问题求助
在Odoo 12中实现Many2many字段的变更追踪
确实,Odoo 12里mail.thread的track_visibility原生就不支持many2many字段——毕竟这类字段是关联集合,系统默认的追踪逻辑只处理单个值的变更,没法自动识别集合里的增删操作。不过我们可以通过重写核心追踪方法来解决这个问题,下面给你两种可行的方案:
方案一:重写_message_track方法(推荐,覆盖所有场景)
这是最全面的解决方案,不管是前端表单修改、后台批量操作还是代码层面的字段变更,都能触发追踪消息。核心思路是扩展mail.thread的_message_track方法,让它能识别并处理many2many字段的变更。
代码示例
from odoo import models, fields, api class YourTargetModel(models.Model): _name = 'your.target.model' # 替换成你的模型名称 _inherit = ['mail.thread'] # 确保模型继承mail.thread # 定义你的many2many字段,保留track_visibility标记 related_partners = fields.Many2many( 'res.partner', string="关联合作伙伴", track_visibility='onchange' ) def _message_track(self, tracked_fields, initial_values): # 先调用父类方法处理普通字段的追踪 res = super(YourTargetModel, self)._message_track(tracked_fields, initial_values) for record in self: # 遍历所有被标记为追踪的字段 for field_name in tracked_fields: field_info = tracked_fields[field_name] field = record._fields[field_name] # 只处理many2many类型且track_visibility为onchange/always的字段 if field.type == 'many2many' and field_info.get('track_visibility') in ['onchange', 'always']: # 获取初始值和当前值 initial_records = initial_values.get(record.id, {}).get(field_name, record.browse()) current_records = record[field_name] # 计算新增和移除的记录 added_records = current_records - initial_records removed_records = initial_records - current_records if added_records or removed_records: msg_segments = [] if added_records: added_names = ', '.join([rec.display_name for rec in added_records]) msg_segments.append(f"添加了: {added_names}") if removed_records: removed_names = ', '.join([rec.display_name for rec in removed_records]) msg_segments.append(f"移除了: {removed_names}") # 组装消息内容并发送 track_message = '; '.join(msg_segments) record.message_post( body=f"<p><b>{field.string}</b> 已变更: {track_message}</p>", message_type='notification', subtype_id=self.env.ref('mail.mt_note').id ) return res
关键说明
- 这段代码会自动对比
many2many字段的初始值和当前值,识别出新增/移除的记录 - 生成的消息会直接出现在模型的聊天流中,和原生字段的追踪消息格式保持一致
- 支持所有触发字段变更的场景,包括前端编辑、后台批量修改、API调用等
方案二:通过onchange方法手动触发(仅前端场景)
如果你只需要处理前端表单的修改,可以直接给many2many字段添加onchange方法,手动生成追踪消息。不过这种方式无法覆盖后台操作和代码变更的场景。
代码示例
from odoo import models, fields, api class YourTargetModel(models.Model): _name = 'your.target.model' _inherit = ['mail.thread'] related_partners = fields.Many2many( 'res.partner', string="关联合作伙伴", track_visibility='onchange' ) @api.onchange('related_partners') def _onchange_related_partners(self): # 仅对已有记录生效(新建记录没有origin) if self._origin.id: initial_records = self._origin.related_partners current_records = self.related_partners added_records = current_records - initial_records removed_records = initial_records - current_records if added_records or removed_records: msg_segments = [] if added_records: added_names = ', '.join([rec.display_name for rec in added_records]) msg_segments.append(f"添加了: {added_names}") if removed_records: removed_names = ', '.join([rec.display_name for rec in removed_records]) msg_segments.append(f"移除了: {removed_names}") track_message = '; '.join(msg_segments) self.message_post( body=f"<p><b>{self._fields['related_partners'].string}</b> 已变更: {track_message}</p>", message_type='notification', subtype_id=self.env.ref('mail.mt_note').id )
注意事项
- 确保你的模型已经正确继承
mail.thread,否则消息无法发送到聊天流 - 如果
many2many关联的模型没有display_name字段(或者你想显示其他字段),可以替换成对应的字段名称(比如name) - 测试时要覆盖所有变更场景:新增记录、移除记录、全选/清空集合等,确保消息生成正确
内容的提问来源于stack exchange,提问作者nguyen thanh Dinh
相关产品推荐
相关产品推荐

