Odoo 开发

Odoo 的 display_name 不是“显示用字段”这么简单:_rec_name、_search_display_name 与 name_create 边界讲透

很多人把 display_name 当成一个普通展示字段,但 Odoo 官方源码里,它其实串起了对象如何显示、如何被 name_search 命中,以及没有 _rec_name 时的兜底行为。本文讲清显示名、搜索名和快速创建之间的真正边界。

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

很多 Odoo 初学者会把 display_name 理解成“给界面显示的一列文字”。这不算错,但远远不够。

在官方 ORM 里,display_name 其实是一个很核心的接口层概念。它不只是决定“看起来显示什么”,还会影响:

  • 关系字段下拉里怎么展示
  • name_search() 怎么搜
  • name_create() 如何快速创建
  • 没配置 _rec_name 时系统怎样兜底

所以它不是简单 UI 字段,而是 对象对外可识别名称的统一协议

一、display_name 默认怎么来

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

  • 如果模型定义了 _rec_name
  • 就把 _rec_name 对应字段转换成显示值
  • 否则退回成 model_name,id

这说明一件事:

display_name 的默认中心,不是固定叫 name 的字段,而是 _rec_name

所以很多模型虽然没有直接拿 name 做显示,但只要 _rec_name 指向别的字段,界面上看到的显示名就会跟着变。

二、为什么搜索显示名时,不是直接搜 display_name

另一个很关键的方法是 _search_display_name()

它不是去数据库里找一个真实叫 display_name 的列,而是根据:

  • _rec_names_search
  • _rec_name

把“搜索显示名”翻译成真正的 domain。

默认逻辑会:

  • 对普通字段按 operator 生成搜索条件
  • 对关系字段继续搜关联对象的 display_name
  • 对不同操作符尝试做类型转换

这意味着 display_name 搜索并不是一个简单的“搜文本列”,而是一个 由 ORM 动态翻译的搜索语义

也正因为这样,不同模型完全可以重写它,改成更符合业务直觉的搜索行为。

源码里 name_search() 很值得看,因为它没有自己搞一套复杂搜索,而是:

  1. 构造 Domain('display_name', operator, name)
  2. 再叠加额外 domain
  3. search_fetch(..., ['display_name'])
  4. 返回 (id, display_name) 列表

这告诉我们:

  • name_search() 是一个关系字段候选入口
  • 真正的搜索语义落在 _search_display_name()
  • 真正的展示值又落回 display_name

也就是说,显示和搜索看似两件事,其实被同一套协议串了起来。

四、name_create() 为什么看起来简单,却很依赖 _rec_name

name_create() 的默认实现更简单:

  • 如果有 _rec_name
  • 就直接 create({self._rec_name: name})
  • 然后返回 (id, display_name)
  • 如果没有 _rec_name,就只能警告并返回失败值

这说明快速创建并不是“随便创建一个对象”,它默认假设:

  • 这个模型存在一个适合作为快速输入主标识的字段
  • _rec_name 就是那个入口

所以有些模型能在 many2one 下拉里顺滑“边输边建”,有些模型就不适合,根本原因不在前端,而在模型命名协议本身。

五、为什么很多模型会重写这套逻辑

官方的 res.partner 就不是完全照搬默认行为。它通过 _rec_names_search 把:

  • complete_name
  • email
  • ref
  • vat
  • company_registry

都纳入候选搜索字段。

这很合理,因为联系人在真实业务里,用户想用来找人的关键词从来不止名字。

这也说明一个实战原则:

  • 如果你的模型“显示用主名”很简单,默认 _rec_name 足够
  • 如果用户真实搜索习惯很多样,就该认真设计 _search_display_name()_rec_names_search

六、新手最容易混淆的几个点

1)“display_name 就是数据库里的 name 列”

不是。它默认依赖 _rec_name,甚至可能完全由自定义计算逻辑决定。

不完全对。它更多是入口封装,真正翻译搜索条件的是 _search_display_name()

3)“name_create 就是所有模型都能用的快速创建”

也不是。没有合适 _rec_name 的模型,默认并不适合这样建。

七、实战里怎么设计更稳

如果你在做自定义模型,可以先问自己三个问题:

  1. 用户看到这条记录时,最自然的名称是什么?
  2. 用户搜它时,会用哪些关键词?
  3. 这个模型适不适合只靠一个文本值快速创建?

这三个问题分别对应:

  • display_name / _rec_name
  • _search_display_name / _rec_names_search
  • name_create

想清楚它们,many2one 体验通常会顺很多。

结语

display_name 真正重要的地方,不是“界面显示哪串字”,而是它把 显示、搜索、快速创建 三件事串成了一套统一命名协议。

理解这套边界后,你会发现很多关系字段体验好不好,并不主要取决于前端,而取决于模型层有没有把“对象该如何被人识别”设计明白。

DISCUSSION

评论区

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