fields_get 元数据

Odoo 的 fields_get 为什么不只是“列出字段”:动态字段元数据、权限过滤与上下文改名链路讲透

很多人以为 fields_get 只是把模型字段列出来,实际上它是 Odoo 返回字段元数据的关键入口。本文结合官方源码讲清 fields_get 如何做权限过滤、翻译、readonly 修正,以及为什么同一个字段在不同上下文下标签会变。

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

先说结论

很多开发者第一次接触 fields_get(),会把它理解成:

  • “把字段列表吐出来”
  • “给导入导出或 API 看一下字段”

但它在 Odoo 里的真实角色更接近:

模型对外公开“字段元数据”的统一入口。

它返回的不只是字段名,还包括:

  • string
  • help
  • type
  • readonly
  • required
  • selection
  • searchable
  • 以及其他描述属性

更重要的是,这些返回值并不是永远固定的。


官方源码里的 fields_get() 在做什么

/home/ubuntu/odoo-temp/odoo/orm/models.py 里,fields_get() 的逻辑非常清楚:

  • 遍历 self._fields
  • allfields 过滤目标字段
  • 先检查当前用户是否有字段级读取权限
  • 再调用 field.get_description(self.env, attributes=attributes) 生成描述
  • 如果 description 里有 readonly,还会结合写权限进一步修正

最后返回的是:

  • 一个以字段名为 key 的字典
  • value 是该字段的描述字典

这里最值得注意的是三点。

1. 它会做字段级权限过滤

所以 fields_get() 不是“模型有啥就全吐啥”,而是:

当前 env 允许你看到什么字段元数据,才给你什么。

2. 它的 string / help / selection 会走翻译语境

源码注释直接写了:

  • _inherits 带来的字段也会包含进来
  • stringhelpselection 等描述会按当前语言翻译

3. readonly 不是机械照抄 field 定义

如果用户对这个字段没有写权限,返回描述里可能会把它视作只读。

这说明:

字段元数据不是纯静态 schema,而是“当前语境下的可用描述”。


为什么同一个字段标签会在不同地方看起来不一样

如果你只把字段理解成“数据库列定义”,你会很困惑:

  • 为什么同一个字段在不同界面标题不一样?
  • 为什么有时叫 Forecasted Quantity,有时又不是?
  • 为什么某些自定义字段在某个用户下像不存在?

答案之一就是:fields_get() 可以被模型重写,并且经常会结合上下文动态改描述。

官方源码里就有很好的例子。

stock.product 的上下文改名

/home/ubuntu/odoo-temp/addons/stock/models/product.py 中,fields_get() 会读取:

  • location
  • search_location

然后根据库位 usage 动态改字段标签。

比如:

  • supplier 库位下,qty_available 会显示成 Received Qty
  • internal 库位下,virtual_available 会显示成 Forecasted Quantity
  • customer / inventory / production 下又会有不同文案

这非常能说明问题:

同一个字段,字段本体没变,但它面对当前业务语境时,描述可以变。


为什么 fields_get() 不是单纯给前端看的

它当然会被前端、导入导出、API、视图后处理等地方使用。

但更本质地说,它解决的是:

系统怎样把“模型内部字段定义”转换成“当前用户当前语境下可消费的字段说明”。

这也是为什么很多框架逻辑都要依赖它,而不是直接去扒 _fields

因为 _fields 更接近模型定义本身; 而 fields_get() 更接近“解释给外部系统听”的那一层。


res.users 的例子为什么更能说明权限语义

/home/ubuntu/odoo-temp/odoo/addons/base/models/res_users.py 里,fields_get() 还做了一个很典型的补丁:

  • 先拿父类结果
  • 再把“用户自己可读/可写”的字段补回来
  • 对补回来的字段动态标记 readonlysearchable=False

这说明 fields_get() 不只是“把 field description 原样往外倒”,而是能表达:

  • 哪些字段当前可见
  • 哪些字段当前可写
  • 哪些字段虽可读但不适合作为普通搜索元数据暴露

也就是说,它是一个权限 + 元数据解释层


开发里最常见的误解

误解 1:fields_get() 等于数据库字段定义

不是。

它更像“当前语境下的字段说明书”。

误解 2:字段标签改了,就等于字段本体改了

很多时候你只是改了 fields_get() 返回的 string,不是改字段定义本身。

误解 3:直接读 _fields 就够了

如果你只关心模型类定义,读 _fields 可以。

但如果你关心:

  • 当前用户能看到什么
  • 字段在当前语言里叫什么
  • 当前上下文下标签怎么变

就不能跳过 fields_get()


实战里什么时候该考虑重写 fields_get()

比较适合的场景有:

  • 字段标签确实需要随上下文变化
  • 某些字段元数据需要按权限做额外包装
  • 你要给前端或外部调用返回更贴业务语义的字段描述

但也别滥用。

如果只是想改固定标签,优先:

  • 字段定义
  • 翻译
  • 视图层

因为一旦把太多展示逻辑塞进 fields_get(),你就会让字段元数据变成一个隐藏副作用层,调试成本会上升。


一句话收尾

fields_get() 不是“字段列表接口”,而是 Odoo 把字段定义翻译成“当前用户、当前语言、当前上下文可消费元数据”的解释层。

DISCUSSION

评论区

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