规则调试

Odoo 记录规则为什么一到 sudo 就像失踪了:_get_rules 空结果、_compute_domain 缓存键与调试误判

不再泛讲 domain_force 拼装,而是聚焦调试现场最常见的误判:开发者用 sudo 测 ir.rule,结果 _get_rules 直接返回空集合。文章只讲 sudo、allowed_company_ids 缓存键与 rule 调试顺序。

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

这篇只回答一个调试现场问题

很多人第一次排查 ir.rule 时,都会做一个看似合理的动作:

  • 切到 shell
  • sudo() 一下模型
  • search()_compute_domain()
  • 然后得出结论:这条记录规则根本没生效

问题是,这个结论经常从第一步就已经歪了。

因为在 Odoo 源码里,sudo() 不是“更方便地观察规则”,而常常是“直接不再参与规则”。

这篇不再泛讲 domain_force 怎样 AND / OR 拼装,而只讲一个最容易造成调试幻觉的点:

  • sudo_get_rules() 为什么会直接返回空规则集
  • allowed_company_ids 为什么又会让结果看起来像“忽然变了”

_get_rules() 最关键的分支:self.env.su

odoo/addons/base/models/ir_rule.py 里,_get_rules() 很早就有一个判断:

  • 如果 self.env.su
  • 直接返回空的 ir.rule recordset

这意味着什么?

意味着你一旦在 superuser 环境里测试:

  • 不是“拿到所有规则”
  • 不是“规则照算,只是权限更高”
  • 而是这层规则压根不参与计算

所以很多“我在 sudo 下能看到全部记录,所以 rule 没生效”的判断,本身就没有测试到 rule。

你看到的不是规则结果,而是绕过规则后的结果。

为什么这个设计其实很合理

ir.rule 本来就是针对普通访问路径加的安全边界。

如果 superuser 还继续被记录规则约束,会出现很多维护问题:

  • 管理操作被自己配置的 rule 卡住
  • 数据修复工具无法越过业务限制
  • 系统级行为和普通用户行为混在一起

所以 Odoo 的态度非常明确:

sudo 是绕过安全边界,不是观察安全边界。

也正因为如此,调试记录规则时最忌讳的就是拿 sudo 结果当证据。

_compute_domain() 为什么又让人觉得“像在生效”

另一个容易误导人的地方是 _compute_domain() 带缓存。

源码里它使用 ormcache,而缓存键包含:

  • uid
  • su
  • model_name
  • mode
  • tuple(self._compute_domain_context_values())

_compute_domain_keys() 默认返回的上下文键里,最重要的是:

  • allowed_company_ids

这意味着同一个模型、同一个用户、同一个操作,只要你变了下面任意一个条件,缓存结果都可能不同:

  • 有没有 sudo
  • 激活公司集合是不是换了
  • 读写删模式是不是变了

如果你没意识到这些键参与缓存,就很容易产生一种错觉:

  • 刚才还像没规则
  • 怎么切个公司又有规则了
  • 或者刚才像有规则,为什么下一次又没了

其实很多时候不是“规则随机失灵”,而是 你换了缓存命中条件。

allowed_company_ids 为什么特别重要

在多公司环境里,记录规则经常会写:

  • company_id in company_ids
  • 或其他依赖当前激活公司集合的判断

_eval_context() 提供给规则求值的 company_ids,本身就来自当前环境中的激活公司。

所以切公司不只是前端体验变化,而是:

  • 规则求值上下文变了
  • _compute_domain() 缓存键也变了

这正是很多“同一个用户同一条 rule,看起来像时灵时不灵”的根源。

最常见的 4 个调试误判

1)用 sudo() 测完后说 rule 没生效

这最常见,也最不靠谱。因为你可能根本没让 rule 参与。

2)切公司后结果变化,就怀疑缓存脏了

很多时候不是缓存脏,而是缓存键本来就包含 allowed_company_ids

_get_rules()_compute_domain() 都按 mode 分开算。不同操作,命中的规则可能不同。

4)把“规则为空”理解成“没有配置规则”

不一定。也可能只是你在 su 环境里。

更靠谱的调试顺序

如果你真想判断一条记录规则有没有生效,建议按这个顺序:

  1. 先确认自己是不是 sudo 环境
  2. 确认当前 mode 是 read、write、create 还是 unlink
  3. 确认当前激活公司集合 allowed_company_ids
  4. 再看 _get_rules() 挑出了哪些规则
  5. 最后才看 _compute_domain() 的组合结果

这个顺序的价值在于:

  • 先判断自己是不是在测规则
  • 再判断测的是哪一套上下文

而不是一上来就把 domain 结果当最终答案。

什么时候 sudo 仍然有用

这并不是说 sudo 毫无价值。

它仍然适合做两类事:

  • 对照查看“绕过规则后”的完整数据集
  • 修复或迁移那些本来就需要越权处理的数据

但如果你的目标是:

  • 证明某条 rule 生效没
  • 解释普通用户为什么看不到某些记录

那 sudo 更像对照组,不是主测试方法。

总结

调试 ir.rule 时,最容易踩的坑不是 domain 写错,而是测试姿势错了。

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

在 Odoo 里,sudo() 常常不是“更清楚地看记录规则”,而是“直接退出记录规则语境”。

再加上一层 allowed_company_ids 参与缓存,你就会明白为什么很多权限问题看起来像玄学,其实只是:

  • 你换了安全上下文
  • 你又把绕过规则的结果当成了规则结果

把这两层先捋清,ir.rule 的调试会容易很多。

DISCUSSION

评论区

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