先说结论
在 Odoo 里,字段加上 tracking=True 之后,Chatter 里出现的“某字段从 A 变成 B”,并不是一个简单的字符串拼接效果。
它背后至少有四层:
- 先判断哪些字段需要追踪
- 再对比旧值和新值
- 把差异转成
mail.tracking.value数据 - 最后挂到
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_iddate:会转成 datetime 形式存储selection:存的是显示标签,不是仅技术值many2one:会存 id 和 display_nameone2many / 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
评论区