权限与记录规则

Odoo 记录规则为什么不是简单 domain:ACL、ir.rule 与 many2many 的特殊分支

解释 Odoo 的 model access、ir.rule 域合并和 read_group 中 many2many 的特殊处理。

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

先说结论

很多人第一次调 Odoo 权限时,都会把问题简化成一句话:

“是不是 domain 写错了?”

其实不是。

Odoo 的权限至少有两层锁:

  1. ACL / model access:你能不能对这个模型做读写删改
  2. record rule / ir.rule:你能不能看到或操作这条具体记录

所以一条记录能不能被访问,往往不是一个 domain 决定,而是多层规则叠出来的结果。


第一层:check_access_rights()check_access_rule()

odoo/orm/models.py 里,这两个旧接口现在都被标成 deprecated,但它们仍然把思路讲得很清楚:

def check_access_rights(self, operation, raise_exception=True):
    return self.browse().check_access(operation)

def check_access_rule(self, operation):
    self.check_access(operation)

你可以把它理解成:

  • check_access_rights 先看“模型级权限”
  • check_access_rule 再看“记录级权限”

这就是为什么你在 debug 时,不能只盯着一条 ir.rule 域。


第二层:ir.rule._compute_domain() 是怎么合并规则的

记录规则并不是“有多少条 rule,就把 domain 一条条硬拼起来”。

ir.rule._compute_domain() 做了更细的合并:

  • 先处理父模型继承过来的规则
  • 再取当前模型的规则
  • 全局规则 走 AND
  • 分组规则 先 OR,再并回整体 AND

这个结构非常关键,因为它决定了:

  • 你不是只要满足一个 rule 就行
  • 也不是每条 rule 都完全独立
  • 而是 global 和 group 规则以不同方式叠加

代码里还会对 domain_forcesafe_eval,说明规则域本身也是运行时求值的。


为什么 sudo() 经常让你“看起来像权限好了”

sudo() 不是“改个函数名而已”。

它会改变当前环境的访问边界,让你绕过用户上下文看到的数据更宽。

这就是为什么很多权限 bug 会出现一种假象:

  • sudo() 下正常
  • sudo() 就报错

这时别急着改 domain,先想:

到底是 ACL 卡住了,还是 record rule 卡住了?


read_group 里那个 many2many 特殊分支,为什么值得单独记

addons/web/models/models.py 里,有一个非常值得注意的注释:

# Special case for many2many because (<many2many>, '=', False) domain bypass ir.rule.

为了避免这个洞,Odoo 对 many2many 分组值做了特殊处理:

  • 空值时用 not any
  • 有值时用 = 搭配具体 id

这意味着:

某些看起来“语法上完全合法”的 domain,在权限层面却可能绕开 record rule。

所以 read_group 这段代码不是普通的 UI 辅助,而是在补一个权限漏洞边界。


最容易误判的几个点

1)把 ACL 和 record rule 混为一谈

ACL 解决“你有没有这个动作的资格”,record rule 解决“你能不能碰这条数据”。

2)把 domain 问题当成唯一原因

有时问题不在 domain 本身,而在 company、active_test、用户组、父模型继承规则。

3)忽略缓存

ir.rule 的 domain 计算有缓存,改完规则后不重启或不清缓存,排查时会很迷惑。


实战排查顺序

如果你在做权限排障,建议按这个顺序查:

  1. 先看模型 ACL 是否允许动作
  2. 再看当前用户是否命中 record rule
  3. 然后检查公司上下文和用户组
  4. 最后才去看 domain 语法和 UI 分组字段

read_group 特别要注意 many2many 分支,不要以为所有 domain 行为都一样。


一句话总结

Odoo 的权限不是“一个 domain 过滤器”,而是 ACL、record rule、上下文和特殊字段分支共同组成的访问系统。

只看 ir.rule 不够,只有把模型权限、记录规则和 read_group 的 many2many 特例一起看,才能真正解释权限行为。

DISCUSSION

评论区

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