ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Odoo 17中文数据字典生成实战:从ORM元数据到团队开发基线

Odoo 17中文数据字典生成实战:从ORM元数据到团队开发基线

简介:为 Odoo 17 整理的中文数据字典,面向企业信息化实施、ERP 二次开发及 Odoo 学习者,帮助快速定位数据库表结构与字段含义,减少在官方英文文档和源码中反复翻找的时间。整个资料压缩为一个 PDF 文件,大小约 8.07MB,便于下载后离线查阅和关键词搜索。内容由 Navicat 生成并翻译为中文,目录按服务器、数据库、模式、表逐级展开,覆盖 account_account、account_account_tag、account_account_account_journal_rel 等财务与基础资料模块的核心表,每个表均列明字段名、数据类型、键约束及中文注释,同时清晰呈现表间关联关系,可直接用于二次开发、报表定制、权限梳理和运维排查。目前已有 133 人次学习下载,适合需要系统理解 Odoo 17 数据模型的中高级开发人员、实施顾问,也适合希望深入掌握 ERP 底层结构的爱好者,学习时对照数据字典可快速理解各模块的数据流转,提升开发与配置效率。

1. 拿到「Odoo 17 数据字典(已翻译为中文)」后,先确认它到底解决哪个问题

当手头拿到一份「Odoo 17 数据字典(已翻译为中文)」,先应确认它的用途:Odoo 17 默认仓库里有上百个数据模型、几千个字段,做二次开发、接口对接、数据迁移时,查一个字段名经常要在界面、源码、数据库三处来回折腾。数据字典就是把模型、字段、类型、关联关系和中文标签整理成一份可检索清单,让开发、实施、数据迁移三个角色在同一份元数据上对齐口径。

它对三类人最有用:写二次开发的工程师,需要快速确认字段技术名、字段类型和继承关系;实施顾问,要把中文标签当作和业务方沟通的桥梁;做数据迁移的,要按字段类型、必填性和关联模型去生成映射表,避免临上线才发现两边字段对不上。

比文档本身更值得关注的是生成方式。生成方式决定了这份数据字典能不能和你当前的数据库对得上,也决定了项目升级到 17.0 后续版本时,能不能低成本重新生成一份。所以下面不讨论「这份文档怎么打开」,而是完整地把「Odoo 17 中文数据字典是怎么产出来的、哪里有坑、怎么让它成为团队基线」讲清楚。

2. Odoo 17 的数据字典从哪来:ir.model、ir.model.fields 与字段类型

2.1 模型的元数据仓库:ir.model 与 ir.model.fields

Odoo 的 ORM 有一个区别于普通 Web 框架的设计:所有注册到系统的模型和字段,都会在数据库里留下持久化的元数据记录。数据字典的原始来源,就是这两张核心表对应的模型。

ir.model每行对应一个模型,里面存了模型的技术名(model字段,例如sale.order)、显示名称(name)、是否 transient 模型、是否 abstract 模型等。ir.model.fields则是字段级的元数据仓库,每个字段一行,包含字段技术名(name)、字段标签(field_description)、字段类型(ttype)、关联模型(relation)、是否存储(store)、是否必填(required)等关键属性。

这两张表在 Odoo 17 中依然存在,而且数据量很可观。以一次典型实施为例,安装销售、采购、库存、财务几个常用模块后,ir.model里会有上千个模型,ir.model.fields里会有几千到上万条字段记录。人肉去源码里翻字段定义完全不现实,从这两张表出发做数据字典才是正路。

提示:ir.model 里既包含业务模型,也包含 Odoo 平台内部的系统模型。生成数据字典时一般要过滤掉 transient 和 abstract 模型,否则文档里会出现大量ir.*、base.*开头、普通业务人员根本用不到的系统表。

2.2 字段类型与关联关系在数据字典里如何表达

字段类型在 Odoo 17 里由ir.model.fields.ttype决定。做数据字典时需要把这层「内部类型」映射成文档里人能看懂的说明。常见类型如下:

ttype(内部值)数据字典里的表达说明
char短文本单行字符串,常见的有name、编号
text长文本多行文本,比如备注
boolean布尔是/否
integer整数数量、序号
float浮点数金额以外的数值
monetary金额常配合currency_id使用
date / datetime日期 / 时间注意 date 不含时分秒
binary附件/二进制文件、图片、电子签名
html富文本邮件正文、说明
selection枚举下拉选项,值对标 key
many2one多对一关联指向另一张表,如partner_id指向res.partner
one2many一对多关联例如订单行order_line属于订单
many2many多对多关联例如标签tag_ids
reference动态引用可指向任意模型
jsonJSON 数据Odoo 17 中出现频率变高,用于扩展属性

对于关联类字段,数据字典里必须给出relation,也就是目标模型的技术名,例如res.partner、product.product。只写「关联」不写目标表,等于没写。另外,selection字段的选项数据并不直接存在ir.model.fields上,而是存放在另一张子表ir.model.fields.selection中,每行对应一个选项。这也会是后面避坑环节里容易踩的地方。

2.3 一份合格的中文数据字典至少要有哪几列

在输出文档之前,先把列设计好。做过几版数据字典之后,我一般会保留下面这些列,少了后面一定会回来补。

列典型示例为什么需要
模型技术名sale.order定位模型
模型中文名销售订单文档可读性
字段技术名x_studio_custom开发时真正用到的名字
字段中文标签客户参考和业务方沟通
字段类型many2one决定怎么取值
关联模型res.partner关联查询、迁移用
必填True / False校验数据完整性
只读True / False界面行为
存储True / False非存储字段不落库,SQL 里查不到
可翻译True / False判断多语言数据是否要额外处理
归属模块sale快速知道字段来自哪个模块
帮助说明help 字段原文字段语义补充

这 12 列是底线。实际项目里,我通常还会加一列「备注」,留给实施人员填写业务叫法。注意:字段标签不一定等于业务叫法,例如技术名x_custom_code的标签可能是「自定义编号」,但业务上叫「客户编码」。备注列就是用来沉淀这类差异的。

2.4 三条生成路线怎么选:源码、运行时、数据库

做 Odoo 17 的中文数据字典,基本有三条路线,区别非常大。

第一条是扫源码:把插件目录里的 Python 模型定义和 XML 视图里的字段声明抓出来。优点是离线可用、不依赖数据库环境;缺点也很明显,Odoo 的字段大量来自继承和 mixin,一个sale.order的完整字段列表分散在十几个模块里,扫源码很容易漏,而且 Studio 自定义字段、数据库里手工改过的结构在源码里根本看不到。

第二条是查数据库:直接用 SQL 查ir_model_fields表。速度快、能覆盖所有持久化字段,但它拿到的是数据库里的原始值,field_description是英文标签,中文翻译要靠额外关联翻译表,字段继承关系也不直观。

第三条是从运行中的 ORM 读取:用 Odoo shell 或自定义脚本调用fields_get(),让 Odoo 自己把继承、动态 selection、翻译全部算好再输出。这也是我推荐的方式。它拿到的是运行时真实字段集合,而且可以按登录语言拿到中文标签,天然能应对 Odoo 的继承机制。

后面第 3 章的脚本就是按第三条路线写的。

3. 用 ORM 生成一份可用的中文数据字典:脚本与参数

3.1 生成前确认两件事:中文语言包与翻译是否就位

在写脚本前,必须先确认数据库里已经启用了中文语言,并且各个模块的中文翻译已经导入。否则脚本就算指定中文,Odoo 也只会退回默认英文标签,生成出来还是半中半英。

常见做法是进入实例的 shell 环境,先做一次语言检查:

python3 odoo-bin shell -d 你的数据库名 --addons-path=addons

然后在 shell 里执行:

langs = env['res.lang'].search([('code', '=', 'zh_CN')]) print(langs.mapped('active')) print(langs.mapped('is_instantiate'))

如果active为 False,说明中文语言没有启用。最常见的补救方式是到「设置 → 语言→ 简体中文」手动激活并加载翻译,也可以在启动时直接带参数:

python3 odoo-bin -d 你的数据库名 --load-language=zh_CN

--load-language=zh_CN会在加载模块后自动安装中文语言并对已有模块导入翻译。这里要特别注意:语言启用是第一步,模块翻译导入是第二步。只启用语言、不导入翻译,或者后来才新增模块而没导入该模块的中文翻译,数据字典里一样会出现英文残留。

提示:自研模块如果没写i18n/zh_CN.po,那这个模块里的字段标签永远不会有中文版。做 Odoo 17 项目时,我一般把中英文翻译文件当作交付物的一部分,和模块代码一起进版本库。

3.2 最小脚本:遍历模型输出 Markdown 数据字典

确认翻译就位后,就可以在 Odoo shell 里直接跑生成脚本。下面是一个最小可用的 Markdown 版本。它遍历非 transient、非 abstract 的模型,对每个模型调用fields_get(),并把字段信息拼成 Markdown 表格。

# 在 odoo shell 中执行,生成 markdown 格式的数据字典 MODEL_DOMAIN = [ ('transient', '=', False), ('is_abstract', '=', False), ] def dump_md(env, output_path='odoo17_data_dict.md'): models = env['ir.model'].search(MODEL_DOMAIN, order='model') lines = [] for m in models: title = f"## {m.name}({m.model})" lines.append(title) lines.append("") lines.append("| 字段技术名 | 中文标签 | 类型 | 关联模型 | 必填 | 存储 |") lines.append("| --- | --- | --- | --- | --- | --- |") fields = env[m.model].with_context(lang='zh_CN').fields_get() for fname, attrs in fields.items(): relation = attrs.get('relation') or '' label = attrs.get('string') or '' ftype = attrs.get('type') or '' required = '是' if attrs.get('required') else '否' store = '是' if attrs.get('store') else '否' lines.append( f"| {fname} | {label} | {ftype} | {relation} " f"| {required} | {store} |" ) lines.append("") with open(output_path, 'w', encoding='utf-8') as f: f.write('\n'.join(lines)) print('done') dump_md(env)

这段脚本的逻辑是:先查ir.model拿到模型列表,再对每个模型调用fields_get()。fields_get()返回的是一个字段技术名到属性字典的映射,比直接查数据库多算好了继承字段和动态 selection,同时with_context(lang='zh_CN')保证拿到的string和selectionlabel 是中文。

参数说明:MODEL_DOMAIN里的transient和is_abstract用来排除向导类模型和抽象基类;order='model'让输出按模型技术名字母排序,方便 diff。fields_get()用来取字段,它会合并当前模型继承到的所有字段,这正是它比扫源码更精确的原因。

3.3 必须按项目调整的几个生成参数

上面只是最小脚本,实际项目中我会按需要调整几个地方。

第一个是模型范围。有些项目只需要输出销售、采购、库存几个核心模块,有些则要全量。如果是全量,建议在脚本里把模型做的再多一层过滤,直接排除平台内部模型:

MODEL_DOMAIN = [ ('transient', '=', False), ('is_abstract', '=', False), ('model', 'not like', 'ir.%'), ('model', 'not like', 'base.%'), ]

第二个是字段范围。Odoo 17 里很多模型继承了mail.thread,会带出message_ids、message_follower_ids、activity_ids等一长串消息字段。做业务数据字典时,这些字段通常应该过滤掉,否则一张订单表里一半是消息相关字段。做法是在循环里判断字段类型或名称前缀,比如:

SKIP_PREFIX = ('message_', 'activity_', 'mail_') ... if fname.startswith(SKIP_PREFIX): continue

第三个是翻译行为。fields_get()返回的字段标签跟当前用户的语言有关。在 shell 里环境语言默认是 en_US,所以必须像示例里那样显式指定with_context(lang='zh_CN')。如果数据库里某些模块的中文翻译本来就没装全,这里依然会返回英文,不要以为脚本出问题。

第四个是输出格式。Markdown 适合放在 Git 仓库里做 diff,也适合直接在代码托管平台上预览。但如果要发给不熟悉 Markdown 的业务人员,最好转成 CSV 或 Excel。常见做法是让脚本多输出一个 CSV 文件,然后由实施顾问用 Excel 打开另存为 xlsx,比让业务方装浏览器插件现实得多。

3.4 补充方案:直接从 ir.model.fields 读取字段归属

fields_get()也不是万能的。它返回的是「当前这个模型实际有哪些字段」,但不会告诉你字段属于哪个模块,也不会暴露 Studio 自定义字段和模块字段的区别。如果要按模块归类,就需要直接读ir.model.fields。

下面这段代码用来补齐字段归属信息:

fields_domain = [ ('model.model', '=', 'sale.order'), ] field_records = env['ir.model.fields'].search(fields_domain) for f in field_records: module_name = f.modules.name or 'studio' label = f.field_description print(f.name, label, f.ttype, module_name)

这段脚本的关键在于f.modules字段。模块字段属于哪个模块,就指向ir.module.module的对应记录;如果该模块字段是 Studio 自定义出来的,modules会是空值,这时我用'studio'占位。field_description在 ORM 查询时会按当前语言做翻译转换,所以这里同样建议用with_context(lang='zh_CN')包一层。

和fields_get()相比,这种方式的优势是能拿到每个字段的模块归属、帮助文本、组权限等更多信息;代价是要自己处理继承字段的重复问题。以sale.order为例,它继承自mail.thread,但ir.model.fields里每个继承字段都会以sale.order为模型再存一条记录,所以直接查询会把message_ids等字段完整带出来,需要脚本里再过滤一次。实践中更稳的做法是:用fields_get()生成主文档,再用ir.model.fields生成模块归属映射表,两张表按字段技术名关联。

4. 生成中文数据字典的避坑清单:5 个常见的翻车点

4.1 字段标签仍然是英文:翻译没进数据库

现象:脚本里已经写了with_context(lang='zh_CN'),生成出来的文档里还是大量英文标签,只有少数字段是中文。

原因:中文语言包虽然启用了,但某些模块的翻译并没有导入。Odoo 的翻译是「语言启用 + 模块导入」两步走,后装的模块如果没走一遍翻译导入,翻译条目就不会出现在数据库里。另一个原因是自研模块代码里直接写了string="Customer Reference"且没有提供中文 po 文件,这种情况无论怎么设置语言都出不来中文。

解决:先确认语言已激活并一次性导入既有模块翻译,再对新装模块执行一次模块升级或重新导入翻译。检查方法很简单,在 shell 里执行:

t = env['ir.translation'].search([ ('lang', '=', 'zh_CN'), ('src', 'like', '%Customer Reference%'), ], limit=1) print(t.value if t else 'NO TRANSLATION')

如果查不到记录,说明翻译确实没导入。对自研模块,则要在模块目录下补i18n/zh_CN.po,并在升级模块时让 Odoo 自动导入。

4.2 继承字段重复刷屏:mixin 字段带出了一堆用不到的记录

现象:生成销售订单的数据字典,里面message_ids、message_follower_ids、activity_ids等消息字段占了半页,真正的业务字段被挤到下面。

原因:Odoo 17 里sale.order等模型继承了mail.threadmixin,fields_get()会把所有继承字段合并进返回结果,而且不会区分「本模型定义」和「从基类继承」。从技术上讲这些字段确实存在,但从业务数据字典的角度看就是噪音。

解决:生成时用字段名前缀过滤掉消息类字段。更稳妥的方式是读取fields_get()返回的inherited属性,它在 Odoo 17 里会标记该字段是否是继承字段。过滤逻辑可以是:

if attrs.get('inherited') and fname.startswith(('message_', 'activity_')): continue

如果不想过滤,也可以把这批字段在文档里统一标为「继承自 mail.thread」,让读者知道它们在每个业务模型里都会出现。两种方式选一个,别不做处理直接全量输出。

4.3 selection 选项只有 value 没有中文 label

现象:字段类型输出为selection时,文档里只有draft、done这样的技术值,业务人员不知道draft到底是「草稿」还是「未提交」。

原因:很多人直接从数据库ir_model_fields_selection子表查选项,那个表里存的是选项的 value 和默认 label,并不会自动映射翻译。即便用fields_get(),如果 selection 的 label 没有翻译条目,返回的也是英文字符串。

解决:在脚本中直接使用fields_get()返回的selection属性,它已经是列表形式,并且会随lang='zh_CN'返回翻译后的 label。注意fields_get()会真实求值动态 selection,如果某个 selection 是函数动态生成,打印出来之前建议先转成字符串,避免 Odoo 只返回一个方法名。示例:

selection_opt = attrs.get('selection') or [] selection_str = '; '.join(f"{v}={label}" for v, label in selection_opt)

这一条在生成中文数据字典时尤其重要,selection 是字段值语义的最后一公里,漏掉它看似小事,实际用起来频繁翻车。

4.4 Studio 自定义字段混进来,标签来源跟模块翻译不是一套

现象:文档里出现x_studio_...开头的字段,标签显示正常中文,但它的 help 或备注是空的,而且不受语言包控制。

原因:Studio 字段由用户在界面里创建,标签是创建时填写的,很多直接就是中文;它不会进入任何模块的 po 翻译体系。对于「已翻译为中文」的语义而言,这类字段实际上是反过来的——它的「翻译」是用户手工输入的原始值。

解决:默认在脚本里把x_前缀字段单独分类输出,并加一列「来源 = Studio 自定义」。如果业务方在意这些字段,就保留并标注;如果这次数据字典只针对标准模块,就把x_字段过滤掉。注意,过滤要放在fields_get()之后,因为 Studio 字段同样会出现在返回结果里。

4.5 字段清单与数据库实际列对不上:非存储字段与历史残留

现象:文档里列出的字段数量和数据库表实际列数对不上,有时候文档有一列数据库没有,有时候数据库有列文档没写。

原因:Odoo 17 里有大量非存储(非 store)的计算字段,它们在 ORM 层存在、可以被界面使用,但不会在数据库表里生成对应列。反过来,某些从旧版本升级上来的数据库里保留了历史字段列,ORM 层早已不注册,但表结构还在。

解决:数据字典里必须保留「存储」这一列。做迁移或写原生 SQL 时,只认存储字段;做业务分析时,计算字段也要带上。如果项目里有数据库整理需求,用信息模式检查实际表列,然后把两份清单做差集对比,快速找出是「缺字段」还是「残留列」:

psql -d 你的数据库名 -c "select column_name from information_schema.columns where table_name = 'sale_order';"

顺便提醒一下:Odoo 17 表名把点号替换成下划线,sale.order对应物理表sale_order。查数据库时别直接复制模型名。

5. 把数据字典落成开发基线的三个技巧

生成一份数据字典不难,难的是让它活下来,成为项目里长期有效的东西。下面是我自己沉淀下来的三个用法。

第一个是把数据字典放进 Git 仓库,和版本升级绑定。每次 Odoo 17 升级或新装模块后,重跑一次生成脚本,然后直接对比前后两份文档:

git diff --stat odoo17_data_dict_before.md odoo17_data_dict_after.md

字段的新增、删除、类型变更都会在这一步暴露出来。相比逐个模块读更新日志,这种方式来得直接,也更适合在代码评审里作为字段变更的凭证。

第二个是额外输出一张「模型关系摘要表」,只保留 many2one 和 many2many 关系,不输出普通字段。几十个模型挨个点开看关联能让人崩溃,但一张关系表放在手边,写报表 join、做数据迁移、梳理接口字段都高效得多。关系摘要表可以由脚本自动生成,本质上就是把上一版文档里的relation列单独汇总。

第三个是给字段加「业务备注」列。数据字典生成时,中文标签是翻译出来的,但业务上怎么叫它、会不会有历史遗留叫法,翻译管不了。我会在实施过程中把「技术名—中文标签—业务俗称」对照表维护在数据字典的同一份文件里,比如在 Markdown 表格末尾追加一列备注。这样后续接手的同事看到的不只是字段名,而是字段和业务的对应关系。

我自己吃过一次亏:某个项目只做了「模型到字段」的正向文档,没整理关联摘要,上线前写迁移脚本时,不得不一个个去界面里点开字段查看关联目标,浪费了大半天。后来每版数据字典都强制带上关系摘要表,并约定每次版本升级都重跑一遍生成脚本。从那时起,数据字典才真正变成了开发基线而不是一次性交差。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表