☰
Odoo 17 数据字典实战指南:用 PostgreSQL 表结构快速看懂数据库
2026/10/11 14:24:50 网站建设 项目流程

简介:这是Odoo 17数据库结构的完整中文数据字典,面向Odoo开发、实施与二次开发人员,帮助快速理清官方核心应用的后端数据表关系。资源为一份PDF文档,由Navicat生成并经过中文整理,系统罗列数据库中public模式下的业务表,涵盖财务、销售、采购、库存等标准模块的表与字段信息,同时标注字段命名、类型及关联关系。涵盖从基础表到关联表的完整目录,对理解Odoo的ER模型很有帮助;由于Odoo通过ORM抽象了数据库结构,很多初学者在排查数据流或编写自定义报表时常苦于找不到底层表,这份字典按模块目录组织,恰好能充当随手查阅的案头手册。压缩包内共1个PDF文件,大小8.07MB,体量轻便,不占用过多空间;目前已有133人学习/下载,适合正在学习Odoo 17或准备进行模块定制、数据分析的开发者参考。

1. 一份 Odoo 17 数据字典,比官方文档更快让你看懂数据库

接手 Odoo 17 项目的人,最怕的不是功能不会配,而是数据库像黑匣子。官方文档把模型讲得头头是道,可真要写 SQL 报表或者排查一个字段报错时,你面对的是 PostgreSQL 里几百张物理表,字段到底叫什么、类型是什么、跟哪张表关联,文档往往帮不上忙。这份已翻译为中文的 Odoo 17 数据字典,就是用 Navicat 从 PostgreSQL 导出的表结构全集,覆盖了以会计模块为主的 public schema 下大批业务表,正好补上这个缺口。适合做二开、写财务报表、做数据迁移、以及刚接手 Odoo 项目需要快速摸清库结构的从业者。一句话:它不能替代源码,但能让你在写任何一条 SQL 之前,先看清字段,少走弯路。

2. 读懂 Odoo 17 的表结构:命名规律、关系表与主键策略

2.1 先看命名规律,半小时建立全局观

打开这份数据字典,第一感觉是表名又多又长,尤其是一大串以account_开头的表。其实 Odoo 的物理表命名非常机械:表名 = 所属模块名 + 模型名的下划线形式。以account.move模型为例,生成物理表就是account_move;account.move.line对应account_move_line;account.journal对应account_journal。也就是说,看到account_前缀,就能直接判断这张表来自会计模块。

我拿到这类数据字典的第一件事,是把表按前缀分组,建立一张速览表。以下是从这份字典里可以直接抄走的清单思路:

表名前缀大致模块归属典型表举例
account_会计与财务account_move / account_journal / account_payment
account_analytic_分析会计(成本中心)account_analytic_account / account_analytic_line
account_bank_statement银行对账单account_bank_statement / account_bank_statement_line
account_fiscal_position税位与税务规则account_fiscal_position / account_fiscal_position_tax
account_payment_term付款条款account_payment_term / account_payment_term_line
account_reconcile_自动对账规则account_reconcile_model / account_reconcile_model_line
account_tax税与税分配account_tax / account_account_tax_default_rel
account_full_reconcile完全对账account_full_reconcile
account_partial_reconcile部分对账account_partial_reconcile

为什么这张表有用?因为它决定了你排查问题的入口。比如报表里发现某个客户余额不对,很多人第一反应去翻account_payment,实际上未核销的应收余额全部沉淀在account_move_line里,你如果按模块前缀去定位,方向就不会跑偏。

还有一类表值得单独拿出来看:以_rel结尾的关系表,比如account_account_account_journal_rel、account_account_tag_account_move_line_rel、account_move_account_move_send_rel。这类表对应 Odoo 模型里的 Many2many 字段,表里通常只有两个外键列,极少有业务含义。看数据字典时把它们和普通业务表区分开,能省很多时间。区分方法很简单:有主键 ID 且字段多的是业务表;字段只有两三个且全是_rel的,直接归类为纯关联表。

判断一个表是不是关系表或业务表,可以看它有没有create_uid、write_date这类审计字段——真正的业务对象基本都有,纯关系表往往连id都没有。

2.2 字段级别:列名、类型与注释怎么对着功能读

表看明白之后,要落到字段。数据字典里每张表会列出字段名、类型、是否可空、默认值和注释,这对写 SQL 帮助最直接。以 Odoo 17 会计模块最核心的account_move为例,这张表就是“凭证”,或者说“发票 + 手工分录”的统一载体。关键字段可以按下表理解:

字段名类型用途说明
move_typevarchar凭证类型:entry 手工分录、out_invoice 客户发票、in_invoice 供应商发票、out_refund 客户退款
statevarchar状态:draft 未过账、posted 已过账、cancel 已取消
journal_idint8所属日记账,关联 account_journal
partner_idint8往来单位,关联 res_partner
invoice_datedate发票日期,手工分录里可不填
amount_untaxednumeric未税金额
amount_taxnumeric税额
amount_totalnumeric含税总额

读懂字段名之后,一个重要的习惯是看类型。Odoo 里金额字段几乎全是numeric,小数精度取决于货币的 decimal places;编码类字段像code通常是varchar且带唯一索引;日期时间字段是timestamp。比如account_move_line表里的date是date类型,而create_date是timestamp,用错类型去查报表时常常莫名其妙查不到当天数据,这是新手最容易犯的错。

再就是对字段的“翻译”要保持警惕。数据字典翻译的是物理表注释,不是 Odoo 界面显示文本。看到reconciled这种字段被译成“已调节”或“已对账”,需要回到业务场景里理解:它是判断这笔分录行是否已经完成对账核销的布尔标记。只有结合“对账”这个业务动作去理解字段,后面写应收账龄报表才不会搞错取数逻辑。

2.3 关系表与外键:看懂数据字典没画出来的线

Navicat 导出的数据字典通常会列出索引与主键,但 Odoo 有一个坑:大部分表之间没有真正的物理外键约束。也就是说,你在这份字典里看不到字段关联关系的连线图,但表与表之间的逻辑关系藏在字段命名里,几乎全部遵循“xxx_id指向哪张表”的规则。

比如account_move里的journal_id,指向account_journal的id;account_move_line里的move_id指向account_move;account_payment里的move_id则指向付款生成的凭证。这是我说的“看字段后缀判断关联”:凡是_id结尾的字段,基本都能在另一张表里找到主键对应。

再比如account_account_account_journal_rel,这个表名拆开是account_account加account_journal,中间用_rel连接,说明这是一个“科目与日记账多对多关系”的表。实际业务含义是:某些日记账限定只能使用特定会计科目,比如银行日记账只能用银行科目。如果你在写 SQL 时想找出“某个科目在哪些日记账里可用”,直接关联这张关系表比翻界面更快。

关系表的字段通常只有两列,列名往往是人名化的,比如account_account_id和account_journal_id,对应到代码里就是 Many2many 两端的字段。看到这里我建议你在数据字典上做一个小标记,把这几个_rel表单独列一组,以后写联表查询时,凡是涉及多对多过滤,都优先想到它们。

提示:Odoo 的 ORM 会自动维护_rel表,千万不要手动往这类表里插数据,也别在视图里直接展示,很容易造成关联数据丢失且不自知。

3. 把数据字典用起来:反查模型、核对字段、写 SQL 的三个落地场景

3.1 场景一:升级或安装模块报“字段不存在”,用字典比翻日志更快

实际开发里最常见的报错是装模块或者升级模块时,页面直接弹出column account_move_line.xxx does not exist。这条报错虽然给了表名和字段名,但很多时候你根本不知道这个字段是本来就该有、还是代码里写错模型了。我的排查习惯是直接打开数据字典,定位到对应表,搜索这个字段名,然后做三个判断:

第一,数据字典里根本没有这个字段,说明当前库里没有安装对应模块,或者字段名写错,优先检查模型定义里的字段名。第二,字段存在但类型对不上,比如代码里定义的是Datetime,字典里显示date,这是字段类型不匹配导致的数据库约束问题。第三,字段存在但前缀不对,比如把sale_order的字段写到account_move里,字典能立刻帮你看出这两张表风马牛不相及。

写完代码之后还能用一条 SQL 做快速验证,这条 SQL 可以反复复用:

SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'account_move_line' AND column_name = 'reconciled';

这段查询从 PostgreSQL 系统表里取指定表的字段信息。table_name换成你怀疑出问题的物理表名,column_name换成报错里提到的字段名。返回有记录,说明字段存在;没有记录,说明模型字段没建上。相比打开 Navicat 看图形界面,这条 SQL 在任何客户端里都能跑,省去来回切换的功夫。

确认字段存在但类型不匹配的情况,比如把date当成timestamp用,会出现在日期边界问题上,这时去 Odoo 源码里找到对应模型定义,把字段类型改一致,再-u升级模块让 ORM 自动同步。不要在数据库里直接改字段类型,因为 Odoo 的 ORM 缓存会认为表结构和模型定义不一致,改完数据库反而更容易把整个模块搞挂。

3.2 场景二:写财务 SQL 报表,先核这三张表

做 Odoo 二开绕不开财务报表。最常碰的物理表就三张:account_move凭证头、account_move_line凭证行、account_partial_reconcile部分对账记录。很多人一开始写应收账龄就翻车,原因是不清楚account_move只存了凭证摘要和总额,真正的借贷明细全在account_move_line里。

一个典型的“已过账客户发票借项合计”查询可以这么写:

SELECT l.partner_id, l.account_id, m.name AS move_name, m.invoice_date, l.debit, l.credit, l.balance FROM account_move_line l JOIN account_move m ON l.move_id = m.id WHERE m.move_type = 'out_invoice' AND m.state = 'posted' AND l.account_id = 12345 ORDER BY m.invoice_date DESC;

这里先解释逻辑:account_move_line是行级流水,debit是借方金额,credit是贷方金额,balance是系统按“借减贷”算好的余额;move_type = 'out_invoice'过滤出客户发票,state = 'posted'过滤掉草稿和已取消凭证;l.account_id指定应收科目。之所以不直接查account_move的amount_total,是因为一张凭证里可能有多行对应不同科目,报表要让科目余额平,就必须从行表出发。

参数说明:l.account_id换成你要查的会计科目 ID,这个 ID 可以从数据字典里account_account表的id字段查到;如果要查供应商应付,把move_type改成'in_invoice'。需要包含未过账数据时,去掉AND m.state = 'posted',但注意草稿凭证里金额可能后续改动,报表统计一般只认已过账。

还有一个容易算错的地方是“对账”。某一行balance为零,并不代表已对账,只有reconciled字段为true才是真正核销完毕。想统计未回款金额,核心是找reconciled = false且balance != 0的分录行。如果想把部分对账的明细也拉出来,才需要再关联account_partial_reconcile看金额拆分。这一层关系数据字典里没有画箭头,但字段名已经提示了:account_move_line上的matched_partial以及account_partial_reconcile里的debit_move_id、credit_move_id,就是把对账明细分摊开的关键。

3.3 场景三:数据迁移前,用数据字典做字段映射底稿

从旧 ERP 迁到 Odoo 17,最忌一上来就写导入脚本。字段跑不通的原因九成是两边字段名和类型没对齐。这份中文数据字典可以直接当成字段映射表的底稿,省去先翻模型再手抄字段的功夫。

我的做法是选一张核心表,比如account_move_line,把数据字典里该表的字段列复制到 Excel,然后加三列:源系统字段、转换规则、是否导入。字段级映射只需要保留少量关键列,模板大概是这样:

Odoo 字段类型源系统字段转换规则
partner_idint8客户编码先查 res_partner 的 id
account_idint8科目编码按 account_account.code 反查 id
debit / creditnumeric借贷金额直接映射
datedate凭证日期源为文本 yyyyMMdd,转 date
refvarchar摘要直接映射
move_idint8凭证号先导入 account_move,回填 id

这里有个迁移时的高频问题:很多新手看到id字段就想把旧系统主键直接带过来,结果一导就撞主键冲突。Odoo 的物理表主键虽然叫id,但它完全允许你重新生成,真正要保证业务唯一的是类似account_account.code(科目编码)、res_partner的 VAT 这类业务字段。迁移前先看数据字典里哪些字段带唯一索引,那才是你映射方案真正要对齐的锚点。

4. 避坑指南:Navicat 生成的中文数据字典,这五个坑最耽误事

4.1 坑一:注释不是全覆盖,翻译和实际界面用词对不上

现象:数据字典里某些字段的注释是空的,或者翻译得生硬,比如reconciled被译成“已调节”,analytic_tag被译成“分析标签”,跟界面上看到的中文标签完全对不上。

原因:Navicat 导出的字典,注释来源是 PostgreSQL 里的COMMENT ON COLUMN。但 Odoo 字段的中文标签是写在模型_("...")里的,并不一定同步到数据库注释,所以字典里的翻译是导出的那一刻手工或半自动生成的,存在缺口。

解决:遇到注释为空或看不懂的字段,回到 Odoo 源码看模型定义,同时结合界面操作理解。更省事的做法是记住“注释仅供参考”,真正判断字段用途靠字段名 + 类型 + 值分布。比如看到一个state字段,直接SELECT DISTINCT state FROM ...看有几种取值,远比注释可靠。

4.2 坑二:数据字典是特定账号的导出快照,跟你实际库不一定一致

现象:按数据字典里的表名去自己库里查,发现表不存在,或者字段数量对不上。

原因:这份字典来自特定数据库的导出,正文目录里能看到大量account_accrued_orders_wizard、account_reconcile_model_line这类表,说明导出时这个库启用了完整会计相关模块。而你自己搭的 Odoo 17 可能只装了部分模块,模块没装,物理表自然不存在。

解决:把数据字典当“参考地图”使用。先通过“设置 → 已安装模块”对比源库装了哪些模块,再决定哪些章节能用。如果字段对不上,以information_schema查到的实际结构为准,不要在没了解模块差异之前就怀疑字典错了。

4.3 坑三:排查字段时拿生产库直接跑 ALTER,容易埋雷

现象:发现某张表缺字段,直接在 Navicat 里手工执行ALTER TABLE ... ADD COLUMN,结果 Odoo 前台页面报错,或者后续升级模块时提示字段类型冲突。

原因:Odoo 的 ORM 在启动时会对比模型定义与物理表结构,并尝试同步。手工加了字段,但模型定义里没有对应字段,升级模块时 ORM 不会删它,却可能在后续迁移时因类型不匹配报错;反过来模型有字段而手工删了列,ORM 启动时又会自动建回去。

解决:只要涉及结构变更,一律通过修改模型定义然后odoo-bin -u module升级来完成。数据字典只用来确认现状,不做变更入口。需要临时实验时,在副本库上操作,确认无误再上正式环境。

4.4 坑四:把物理主键 id 当成业务编号用

现象:写报表时直接拿partner_id去界面上对客户编号,发现对不上,或者迁移时把旧系统流水号硬塞进id字段,导致关联混乱。

原因:Odoo 里id就是 PostgreSQL 自增主键,没有业务意义。真正可读的业务编号往往在name、code、reference等字段里,比如account_journal.code是日记账编码,account_account.code是科目编码。数据字典字段列表里能直接看到这些字段,但如果不养成“先看唯一索引”的习惯,很容易默认 id 可用。

解决:查询用表时,先看数据字典中哪些字段有唯一约束,把这些字段作为可能的业务主键;写迁移脚本时,用旧业务编码反查新系统的 id,再建关联。切忌直接把旧 id 搬过来充当物理主键。

4.5 坑五:把数据字典当成需求文档,结果读不懂业务

现象:字典看了好几遍,字段都知道,但就是不理解“为什么这张表会有这个状态”,或者不知道一个字段什么时候被写入。

原因:数据字典是静态结构,只描述“有什么表、有什么字段、类型是什么”,不描述“这些字段在业务流程里如何流转”。比如account_move.state从 draft 到 posted 再到 cancel,这个流转规则在 Python 代码里,不看代码永远理解不了,也猜不到为什么有些记录没有invoice_date。

解决:数据字典用来定位,源码和日志用来理解。我习惯是先在字典里找到表,再去源码搜对应模型,看@api.onchange、write、action_post等方法,把字段变化串起来。工具配合源码,才能避免拿着地图找不到路的窘境。

5. 进阶:用 psql 把数据字典二次加工成自己的速查表

Navicat 导出的字典是一份静态文档,但数据库结构是活的。我一般会在拿到字典之后,用几条 SQL 把它转成自己常用的速查表,这样线上线下能保持一致。

第一条:搜某个字段关键词,找出哪些表包含该字段。比如想查所有含“备注/说明”字段的表:

SELECT table_name, column_name, data_type FROM information_schema.columns WHERE column_name IN ('name', 'ref', 'note', 'comment') AND table_schema = 'public' ORDER BY table_name;

这段查询的价值在于跨表搜索。information_schema.columns是 PostgreSQL 的系统视图,column_name IN (...)可以换成你自己关心的字段名集合,比如amount_untaxed、balance。改表名或字段名时,这条 SQL 能在30秒内告诉你影响范围,比肉眼翻几百页字典快得多。

第二条:生成一份所有业务表的字段数量统计,快速判断哪些表是主表、哪些是多对多关系表:

SELECT table_name, count(*) AS column_count FROM information_schema.columns WHERE table_schema = 'public' GROUP BY table_name ORDER BY column_count DESC;

结果里字段数量极小(比如 5 以下)的表,大概率是_rel关系表;字段数量 20 以上的,基本是核心业务表。拿到这份名单后,我会重点再核对一次哪些表是迁移、报表的高频对象,把这些表单独做成一个 Excel 工作簿。

第三个技巧是验证字段时的“后悔药”写法。在测试库上核对结构或尝试更新数据时,用事务包住再回滚,避免手滑:

BEGIN; SELECT count(*) FROM account_move_line WHERE reconciled = false; -- 如果发现结果不是预期,直接回滚,不产生任何数据变更 ROLLBACK;

这里BEGIN开启事务,ROLLBACK撤销本事务内所有操作。即使中途跑了一条UPDATE,只要还没COMMIT,都能安全撤销。把这条习惯带进日常排查,能避免不少“手一抖全表更新”的事故。

从那以后,我每次接手新的 Odoo 项目,都会先拿到一份数据字典,然后花半小时跑一遍上面的字段搜索和表统计,再开始写业务 SQL。这一套流程帮我避开了太多因为表结构不清楚而返工的问题。数据字典是死的,查询习惯是活的,希望这份中文版 Odoo 17 数据字典和这篇使用思路,能帮你在接手的项目里少踩几个坑。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询