字段追踪

Odoo 字段改了为什么会自动出现在 Chatter:tracking、_message_track 和 mail.tracking.value 到底怎么串起来

很多开发只知道字段加 tracking=True 会在 Chatter 里显示改动,却没看清中间其实还有字段筛选、旧值对比、tracking value 生成和消息落库几层机制。本文从官方源码把这条链讲透。

Odoo 开发
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

先说结论

在 Odoo 里,字段加上 tracking=True 之后,Chatter 里出现的“某字段从 A 变成 B”,并不是一个简单的字符串拼接效果。

它背后至少有四层:

  1. 先判断哪些字段需要追踪
  2. 再对比旧值和新值
  3. 把差异转成 mail.tracking.value 数据
  4. 最后挂到 mail.message,显示在 Chatter

所以你看到的不是“写日志”,而是:

Odoo 把字段变更先结构化,再渲染成用户能读懂的消息。


为什么这个机制值得开发者懂

因为很多人会把 tracking 想得太轻:

  • 加个参数就好了
  • 反正界面会显示变化

但一旦进入实战,你很快会遇到这些问题:

  • 为什么有的字段改了会显示,有的不会?
  • 为什么 many2one 显示的是名称,不是 id?
  • 为什么 selection 显示的是标签,不是技术值?
  • 为什么有时会发 subtype 消息,有时只是普通 log?

这些问题不搞清楚,就很容易把 tracking 当成“玄学 UI 效果”。


官方源码里的主链路是什么

从官方实现看,主链路大致是这样:

第一步:mail.thread 负责组织追踪

addons/mail/models/mail_thread.py 里,_message_track() 会:

  • 取出要追踪的字段定义
  • 遍历记录
  • 调用 _mail_track() 比较初始值和当前值
  • 得到“哪些字段变了 + tracking_value_ids”

它不是直接输出最终文案,而是先得到结构化差异

第二步:_mail_track() 逐字段比较

addons/mail/models/models.py 里,_mail_track() 会:

  • 遍历追踪字段
  • 取初始值 initial_value
  • 取当前值 new_value
  • 如果没变就跳过
  • 如果变了,就为这个字段生成 tracking values

这一步的重点是:

tracking 的核心不是“记录这次 write”,而是“比较前后值是否真的变化”。

所以不是所有 write 都会在 Chatter 里留下可见痕迹。


mail.tracking.value 为什么这么关键

这个模型是整个机制里最容易被忽略、但最值得理解的一层。

它不是一条“完整消息”,而是一条字段差异结构

比如它会存:

  • 变更的是哪个字段
  • old value 是什么
  • new value 是什么
  • 用什么类型展示
  • 某些场景下的 currency / field_info

也就是说,mail.message 负责承接“这次发生了一个消息事件”,而 mail.tracking.value 负责承接“这次消息里有哪些字段变化细节”。

这两层分开之后,系统才能:

  • 对不同字段类型做不同格式化
  • 在界面里把变更清楚渲染出来
  • 保持变更记录是结构化的,而不是一坨纯文本

为什么 different field types 显示效果不一样

mail_tracking_value.py 会发现,Odoo 会按字段类型分别准备 old/new 值。

比如:

  • char / text / integer / float / datetime:直接存对应值
  • monetary:还会带 currency_id
  • date:会转成 datetime 形式存储
  • selection:存的是显示标签,不是仅技术值
  • many2one:会存 id 和 display_name
  • one2many / many2many / tags:会把记录集合展开成可读名称串

这就是为什么 Chatter 里的 tracking 看起来“像是懂业务的”。

它不是前端临时猜出来的,而是后端在创建 tracking value 时就已经做了类型化处理。


_message_track() 为什么有时发消息,有时只是 log

源码里还有一个很关键的分层:

  • 如果 _track_subtype() 给出了 subtype
  • message_post(...)
  • 否则只要有 tracking values,也会 _message_log(...)

这说明 tracking 不只是“技术比较”,它还和业务消息类型联动。

也就是说:

  • 有些变更只是普通变更记录
  • 有些变更会升级成带 subtype 的业务消息

比如阶段变化、状态变化,常常不仅仅是“值变了”,还代表业务事件发生了。


新手最容易误解的 4 个点

1. 以为 tracking 就是 write 日志

不对。

tracking 的基础单位不是“执行过 write”,而是“字段前后值发生了有意义的变化”。

2. 以为显示文本都在前端拼

也不对。

很多类型化处理在 mail.tracking.value 创建阶段就已经完成了。

3. 以为 tracking=True 就能追一切字段

现实里要看字段类型、访问权限、模型是否走 mail.thread 这条链,以及具体变更是否真的能生成可展示差异。

4. 以为 Chatter 只有一层消息模型

其实至少要分清:

  • mail.message:消息事件
  • mail.tracking.value:字段差异明细

实战开发该怎么用这个理解

如果你在设计一个业务对象,想让 Chatter 真正有价值,我建议这样想:

哪些字段变化对人有意义?

不是所有字段都值得追踪。

真正适合 tracking 的,通常是:

  • 阶段
  • 负责人
  • 关键日期
  • 金额
  • 关键业务状态

哪些变化只是技术噪音?

如果字段经常被系统自动刷新,或者只是内部缓存型字段,追踪出来只会污染 Chatter。

这个变化要不要升级成业务事件?

如果某字段变化本身就代表重要节点,那就不只是 tracking,而应该连 subtype / message 模板一起考虑。


一句话记忆法

tracking=True 不是“自动写一句日志”,而是让 Odoo 把字段前后差异结构化成 mail.tracking.value,再挂到 Chatter 消息里展示出来。

理解这层,你以后看到 Chatter 里的字段差异,就不会只把它当 UI 特效,而会知道它是 Odoo 协同机制里一条很完整的后端链路。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。