链式 related

Odoo related_sudo 不是“一开到底”:链式 related 里哪一跳在 sudo、哪一跳还受限

不再泛讲 related 全景,而是围绕 test_orm 里的 foo_bar_sudo_id_name、foo_bar_id_name 等测试模型,说明 related_sudo 只决定当前 related 字段的求值语义,不等于后续再 related 的字段也自动跟着 sudo。

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

先把误区说清楚

很多人理解 related_sudo 时,会不自觉地脑补成这样:

  • 这条 related 开了 sudo
  • 那整条链以后都“带着 sudo 光环”
  • 后面再 related 它,也会继续自动穿透

这其实说大了。

related_sudo 更准确的语义是:

它决定“当前这个 related 字段”在求值时要不要用 sudo。

它不是一个会沿着字段链无限传播的全局开关。

而 Odoo 官方在 test_orm 里专门放了一组很适合讲这个边界的例子:

  • foo_bar_id
  • foo_bar_sudo_id
  • foo_bar_id_name
  • foo_bar_sudo_id_name

这几个字段放在一起看,误区会非常容易拆开。

odoo/orm/fields.py 里,related 字段初始化时会把:

  • compute_sudo = attrs.get('compute_sudo', attrs.get('related_sudo', True))

这说明 related 的默认倾向是:

  • 如果你没显式关掉,当前 related 字段就按 sudo 语义求值

很多人看到这里,就自然延伸出一个错误推论:

  • 那么所有依赖它的后续字段也会自动一起 sudo

源码并没有承诺这一点。

源码承诺的只是:

  • 这个字段本身 怎么算

至于另一个字段再 related 到它,那已经是 另一个字段自己的定义问题

第二层:为什么 foo_bar_sudo_idfoo_bar_sudo_id_name 特别适合看边界

test_orm 里有两条很值得对照的定义:

  • foo_bar_sudo_id = fields.Many2one(related='foo_id.bar_id', related_sudo=True)
  • foo_bar_sudo_id_name = fields.Char(related='foo_bar_sudo_id.name', related_sudo=False)

这组定义说明什么?

说明官方自己就在测试一种非常典型的链式场景:

  1. 第一跳 foo_bar_sudo_id 是 sudo 求值
  2. 第二跳 foo_bar_sudo_id_name 又显式关掉 sudo

如果 related_sudo 真是“一开到底”,那第二个字段根本没必要再显式写 related_sudo=False

但官方偏偏写了,恰恰说明:

  • 每个 related 字段都在独立声明自己的求值边界
  • 前一跳 sudo,不会替后一跳自动做决定

对照组:foo_bar_idfoo_bar_id_name

另一组定义是:

  • foo_bar_id = fields.Many2one(related='foo_id.bar_id', related_sudo=False)
  • foo_bar_id_name = fields.Char(related='foo_bar_id.name', related_sudo=False)

这组更像“整条链都按非 sudo 语义走”。

跟上一组摆在一起,就能很清楚看出:

  • related 的每一跳其实都像一个独立投影点
  • 你不能因为前面有一跳 sudo,就默认后面所有投影也都自动越权

这也是链式 related 最值得建立的心智模型。

最容易理解错的地方,在于大家会把 related 路径当成一根连续水管。

但从字段定义角度看,更贴切的比喻是:

  • 每个 related 字段都像在当前模型上新开了一个投影窗口
  • 这个窗口用不用 sudo,要看它自己的定义

于是:

  • foo_bar_sudo_id 是一个 sudo 窗口
  • foo_bar_sudo_id_name 又是另一个窗口,而且它自己选择了非 sudo

一旦用“窗口”而不是“水管”去理解,很多误判就会自然消失。

为什么这个边界很重要

如果你误以为 related_sudo 会整链传播,开发上就容易做出两类危险判断:

1)高估可见范围

以为前一跳能算出来,后一跳一定也能稳定拿到值。

2)低估泄露风险

以为只要上游 related 已经用过 sudo,后面就不用再显式审查安全边界。

这两种理解都不稳。

真正稳妥的做法是:

  • 每定义一个 related 字段,就单独判断一次它该不该 sudo。

实战设计建议

如果你在项目里写链式 related,建议按这个顺序判断:

  1. 这一跳 related 是给 UI 稳定展示,还是给分析/过滤/权限敏感逻辑用
  2. 这一跳目标字段是不是敏感字段
  3. 当前模型的访问面是否比目标模型更宽
  4. 这一跳是否应该显式写 related_sudo=False

尤其是第二跳、第三跳 related,别偷懒沿用前一跳的想象。

源码没有替你做这个推断。

总结

related_sudo 最大的误区,不是“大家不知道它默认偏 sudo”,而是:

  • 很多人知道它偏 sudo
  • 却又进一步误以为它会沿整条 related 链自动传播

如果只记一句,就记这句:

related_sudo 影响的是“当前 related 字段怎么求值”,不是“后续所有 related 都自动继承同一权限语义”。

把每一跳都当成独立投影面,你写出来的 related 链才会更安全,也更好解释。

DISCUSSION

评论区

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