XMLID 与引用

Odoo 里的 XMLID 为什么这么关键:env.ref、外部标识与稳定引用到底怎么理解

很多 Odoo 开发天天写 env.ref,却没真正理解 XMLID 在系统里扮演什么角色。本文把外部标识、稳定引用和常见误区讲清楚。

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

先说结论

在 Odoo 里,XMLID 不是一个“好记的别名”,而是一种跨安装、跨升级、跨模块都尽量稳定的外部引用机制

env.ref('module.record_id') 本质上就是:

通过 XMLID 去 ir.model.data 里查真实模型和真实记录 id,再返回那条记录。

所以你平时拿到的不是魔法,而是一套“稳定找对象”的基础设施。


为什么 XMLID 比数据库 id 更值得依赖

数据库 id 最大的问题,是它只在当前库里有意义。

比如:

  • 你在 A 库里,res.partner(7) 可能是管理员公司
  • 到了 B 库里,id=7 可能已经是别的记录
  • 重装演示数据、迁移模块、导入初始化数据后,数字 id 也可能完全不同

这就是为什么 Odoo 大量系统内置记录都不用硬编码数字 id,而用 XMLID。

因为 XMLID 的意义是:

  • 这个记录属于哪个模块
  • 这个记录在模块里的逻辑名字是什么
  • 后续系统如何再稳定地找到它

所以它更像“系统级坐标”,而不只是一个数字主键。


env.ref() 到底做了什么

从官方实现看,Environment.ref() 会调用:

  • ir.model.data._xmlid_to_res_model_res_id()
  • 底层再走 _xmlid_lookup()
  • 最后得到 (res_model, res_id)

然后 Odoo 再 browse(res_id),返回真正的 recordset。

也就是说,env.ref() 不是直接查业务表,而是先查 ir.model.data 这张“外部标识映射表”。

你可以把它想成:

先查通讯录,再去找本人。


ir.model.data 在这套机制里扮演什么角色

它本质上是在保存一条映射关系:

  • module
  • name
  • model
  • res_id

这样做的好处是,模块数据、视图、菜单、动作、分组、邮件模板这些“系统骨架记录”,都可以被稳定引用。

所以 XMLID 不是只服务开发者,它服务的是整个模块化系统。


为什么很多场景必须优先用 XMLID

典型场景包括:

  • 取菜单、动作、视图
  • 取安全组
  • 在安装数据里引用别的记录
  • 在 Python 代码里拿基础配置
  • 在测试里稳定获取样例数据

这类对象如果你用数字 id,后面会非常脆弱。

但用 XMLID,就算数据库 id 变了,只要映射还在,你的代码和数据关系就还能成立。


新手最容易混淆的 4 件事

1. XMLID 不是字段值

它通常不在业务表里当普通字段给你看,而是存放在 ir.model.data 的映射里。

2. env.ref() 找不到时,不一定是“代码错了”

也可能是:

  • 模块没安装
  • 数据没加载
  • XMLID 名字写错
  • 记录被删了

3. XMLID 稳定,不代表记录永远存在

如果那条业务记录后来被删了,env.ref() 仍可能失败,或者查出来后 exists() 为空。

4. 不是所有业务记录都该手工造 XMLID

XMLID 更适合模块初始化数据、需要被别处稳定引用的记录和框架级对象。


一句话记忆法

数据库 id 解决“这条记录现在是谁”,XMLID 解决“系统将来还能稳定找到谁”。

DISCUSSION

评论区

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