先说结论
很多人以为 Odoo 里的 UTM 只是:
- 页面 URL 上多几个参数
- CRM 线索里多几个来源字段
但如果只这么理解,就会低估它的设计。
从官方源码看,utm.mixin 真正在做的是:
把一次匿名访问里的营销来源信号,沿着请求链路保存下来,并在后续建业务记录时自动注入对应字段。
也就是说,它不是孤立字段,而是一条完整链路:
- URL 参数
- HTTP 响应写 Cookie
default_get()读取 Cookie- many2one 值按名字查找或创建
- 最终落到业务记录的
campaign_id / source_id / medium_id
utm.mixin 本身提供了什么字段
在 /home/ubuntu/odoo-temp/addons/utm/models/utm_mixin.py 里,定义很直接:
campaign_idsource_idmedium_id
都是 many2one。
这已经说明一个关键点:
Odoo 不把 UTM 只是当字符串保存,而是倾向于把它结构化成可复用的主数据。
所以来源不是随手贴在记录上的文本标签,而是能在系统里继续聚合、统计、归类的对象。
URL 参数是怎么进 Cookie 的
很多人只看 utm.mixin 模型文件,会漏掉 HTTP 那一半。
在 /home/ubuntu/odoo-temp/addons/utm/models/ir_http.py 中,Odoo 重写了 _post_dispatch(),并在里面调用 _set_utm()。
_set_utm() 做的事情很明确:
- 检查请求参数里有没有
utm_campaign / utm_source / utm_medium - 如果有,而且当前 Cookie 值不同
- 就往响应里写入:
odoo_utm_campaignodoo_utm_sourceodoo_utm_medium
而且默认保存 31 天。
这意味着:
UTM 信号并不是只在“这一跳请求”里存在,而是被延续到了后续访问。
这正是“访问来源能影响后来建单”背后的关键。
业务记录是怎么自动拿到这些值的
答案在 utm.mixin.default_get()。
源码逻辑大致是:
- 先走父类
default_get() - 然后逐个检查
tracking_fields()里定义的来源映射 - 如果当前要创建的字段里包含这些 UTM 字段
- 且当前 request 存在
- 就从 Cookie 里取对应值
- 如果字段是 many2one 且 Cookie 里是字符串,就
_find_or_create_record() - 最后把结果塞进默认值
这说明 utm.mixin 的思路不是“等你提交表单时手写映射”,而是:
在 ORM 默认值阶段,就把来源字段自动补进去。
这设计很漂亮,因为它让:
- 网站表单
- 线索创建
- 其他继承
utm.mixin的对象
都能复用同一条默认值注入链。
为什么源码里还特地处理 many2one 的查找/创建
因为 Cookie 里拿到的通常是字符串,比如:
- Spring Campaign
但模型字段是:
utm.sourceutm.mediumutm.campaign
这些主数据表的 many2one。
所以 _find_or_create_record() 会:
- 先按名字模糊找
- 找不到再创建
- 某些模型还会补
is_auto_campaign
这一步很重要,因为它把“前端来源文本”转成了“后端结构化对象”。
也因此,utm.mixin 不是简单埋点,而是埋点到业务主数据的桥接层。
为什么有个“销售员默认忽略 UTM”的判断
源码里还有个很容易忽略的逻辑:
- 如果当前用户不是 superuser
- 且属于销售员组
default_get()就直接返回,不去吃这些 UTM 值
这说明 Odoo 也在防止某些内部人工操作把匿名来源信号不当地继承进去。
换句话说:
UTM 更偏向“外部访问来源带进来的默认语义”,而不是所有后台人工建单都机械套用。
这能减少来源污染。
最常见的误解
误解 1:UTM 只是前端统计参数
不对。
在 Odoo 里,它还会进入 ORM 默认值链路,最终影响业务记录字段。
误解 2:来源字段一定要前端表单自己传
不一定。
很多时候,Cookie + default_get() 已经替你串好了。
误解 3:来源值只是字符串,不值得结构化
官方正相反:它尽量把来源结构化成 many2one 主数据。
对自定义开发最有价值的启发
如果你要让自定义对象也带来源归因,思路往往不是:
- 自己在控制器里东拼西凑
- 提交表单时手工塞三个字段
而是优先考虑:
- 让对象继承
utm.mixin - 明确你是否需要扩展
tracking_fields() - 想清楚哪些对象该自动继承来源,哪些不该
这样你接的是 Odoo 现成的链路,而不是另起一套半自动规则。
一句话收尾
utm.mixin的价值不只是“记录来源”,而是把 URL 参数、Cookie、默认值注入和主数据结构化串成了一条完整归因链。
DISCUSSION
评论区