Odoo 开发

Odoo 的 fields_get 不只是“拿字段定义”:字段级可见性与只读判定是怎么混进去的

很多人把 fields_get 当成表单元数据接口,但官方源码里它还会先过滤字段读权限,再根据写权限改写 readonly 结果。本文讲清 fields_get 为什么会直接影响前端看到什么、能不能改什么。

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

很多人第一次接触 fields_get(),会觉得它只是个“拿模型字段定义”的方法:返回 string、type、required、selection 之类元数据,供前端画表单用。

这当然没错,但如果只把它看成“字段说明书”,你会漏掉它非常关键的一层:权限裁剪

在官方源码里,fields_get() 并不是无条件把 _fields 全吐出去,而是会先判断当前用户有没有读这个字段的资格;即使字段能读,还会根据写权限把返回结果里的 readonly 调整掉。这意味着它不是纯描述接口,而是 描述 + 权限投影 的混合入口。

一、源码里 fields_get() 真正在做什么

/home/ubuntu/odoo-temp/odoo/orm/models.py 里,fields_get() 的主流程不复杂:

  1. 遍历模型的 _fields
  2. 如果调用方指定 allfields,只保留目标字段
  3. _has_field_access(field, 'read') 判断能不能读
  4. field.get_description() 生成字段描述
  5. 如果描述里有 readonly,再结合写权限补一次判断

重点就在第 3 步和第 5 步。

也就是说,fields_get() 返回的不是“字段客观真相”,而是:

当前用户在当前环境下,被允许看到的字段描述。

二、为什么它会直接影响前端“看得见什么”

很多 Web 端视图加载、字段说明、动态 UI 构建,本质上都依赖字段元数据。如果某个字段在 fields_get() 里直接被过滤掉,那前端通常连“这个字段存在”都不会正常感知到。

所以字段级 groups 限制,不只是“写不了”,很多时候是:

  • 看不到
  • 拿不到描述
  • 视图解释阶段就不会当成普通可读字段处理

这也是为什么某些权限问题看起来像“字段消失了”,而不只是“按钮变灰了”。

三、readonly 为什么不是只看字段定义本身

很多人以为 readonly=True 才会让前端只读,其实 fields_get() 里还有一道补充逻辑:

if 'readonly' in description:
    description['readonly'] = description['readonly'] or not self._has_field_access(field, 'write')

这段逻辑非常关键。它表达的是:

  • 字段本身定义成只读,那当然只读
  • 即便字段定义上不是只读,只要当前用户没写权限,返回给前端时也会被视为只读

所以前端看到的 readonly,不完全等于模型声明,而是:

字段声明的只读性 + 当前用户的写权限结果

这也是为什么同一张表单,不同用户打开时,感受到的可编辑性会不同。

四、_has_field_access() 才是字段级权限的真正门卫

同一文件里的 _has_field_access() 规则很直接:

  • 字段没配 groups,或者当前是 superuser → 允许
  • 字段 groups 是 NO_ACCESS → 直接拒绝
  • 否则看当前用户是否属于这些 group

这个设计说明 Odoo 的字段级权限,不是单靠模型 ACL 或记录规则撑起来的。字段本身就能声明一层“谁能看/谁能改”的门槛。

也因此,开发里要区分三种边界:

  1. 模型能不能访问
  2. 记录能不能看到
  3. 字段能不能暴露

很多排错之所以绕,是因为大家只盯前两层,漏了第三层。

五、为什么 res.users 又看起来有点“例外”

/home/ubuntu/odoo-temp/odoo/addons/base/models/res_users.py 里,res.users 重写了 _has_field_access(),允许用户对“自己那一份”某些安全字段有额外读取权限。

这很有代表性。

它说明字段级权限并不是一个死板总开关,而是可以按模型语义扩展。例如用户档案里,系统可能希望:

  • 普通用户不能读很多管理字段
  • 但对自己的某些资料字段,仍然应该能看

所以你看到的最终字段可见性,是:

  • 通用字段 groups 规则
  • 模型定制的 _has_field_access()
  • 当前记录是否“就是自己”

共同作用的结果。

六、新手最容易误解的 3 件事

1)“fields_get 只是文档接口,不影响权限”

错。它直接就是权限投影层的一部分。

2)“字段只读一定是 XML 或 Python 定义出来的”

不完全对。用户没写权限时,fields_get() 也会把它表现成只读。

3)“字段消失一定是视图 XPath 写坏了”

不一定。很可能是字段级读权限把它从元数据里直接裁掉了。

七、实战排错时该怎么想

如果你遇到“某字段在界面上不见了 / 变只读了 / 某用户和管理员看到的不一样”,排查顺序最好是:

  1. 先确认模型 ACL 和记录规则
  2. 再看字段本身有没有 groups
  3. 再确认模型是否重写了 _has_field_access()
  4. 最后才去怀疑视图层 XPath、attrs 或 modifiers

这样通常会比一上来死查 XML 快很多。

结语

fields_get() 之所以重要,不是因为它能返回字段说明,而是因为它把 字段描述字段级权限结果 合在了一起。

所以它从来不是“单纯元数据接口”,而是前端可见性、可编辑性和字段暴露范围的关键中间层。把这层想清楚,很多“为什么这个字段在某个用户眼里像不存在”之类的问题,都会瞬间好排查很多。

DISCUSSION

评论区

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