简介:Odoo 16按部就班实战精解基础篇是一套面向ERP初学者和Odoo二次开发者的视频+源码配套资源,覆盖从基础安装、模块创建到业务配置的完整路径,帮助读者在缺少现场指导时也能按步骤完成Odoo 16环境搭建与功能定制。资源共包含554个文件,以233个py后端逻辑源码、202个xml视图与菜单定义、43个mp4分阶段操作录屏为主,辅以38个csv权限表和37张png界面截图,整包约461.73MB,视频与源码按阶段一一对应,便于边看边练。实战内容聚焦Odoo 16新增的库存预测与保留释放、供应商发票自动匹配、销售流程优化、集团集采SRM以及生产制造补货策略等企业高频场景,每个模块都给出可直接运行的Python模型和视图配置,可对接真实业务需求进行二次开发。目前已有253人学习下载,无论作为系统学习Odoo的基础教程,还是快速了解新功能特性的参考手册,都能显著降低上手门槛。
1. Odoo 16 实战不要跳步:按部就班的前提是把环境当成系统来建
把 Odoo 16 从零跑起来这件事,我见过不少开发者在同一条路上卡住:照着网上的片段装到一半,前端样式丢失、模块列表为空、视图报字段找不到,最后只能删掉虚拟机重来。Odoo 16 是本地化部署场景里最常用的一代长期支持版本,真正难的不是点击鼠标配业务,而是环境、配置、模块骨架和数据视图这四个环节必须按顺序打通。这篇笔记就把这条链路拆成可复现的步骤:装在哪、怎么起、最小模块怎么写、常见坑在哪、调试怎么验证。适合第一次接手 Odoo 16 的企业 IT 和独立开发者,目标是让你照着做一次跑通,而不是把时间耗在排错上。
2. 装在哪、怎么选:Odoo 16 需要的最小环境
2.1 版本选型:为什么基础篇只谈 Odoo 16
Odoo 16 属于长期支持版本,社区资料和第三方模块积累都相对完整,配置语法和视图结构与 17、18 没有本质差异,但网上能搜到的中文排错经验明显更多。对初学者来说,追新版本不是不可以,只是很多报错在刚发的前半年连官方 issue 里都还没有答案,最后只能自己翻代码,属于典型的“为了追新而翻车”。
我看到很多团队最后停留在 Odoo 16 的真实原因不是不思进取,而是业务模块跑在 16 上稳定,二次开发改动的面可控。基础篇选 16 还有一个技术理由:它的 Python 依赖在 3.8 到 3.10 之间兼容性最好,部署环境选型余地大,不会因为系统自带 Python 版本太新被迫升级一堆底层库。
版本选型上我不建议一上来就研究 Docker 镜像的高可用方案。单机部署、源码方式跑通,这是把 Odoo 16 吃透的第一课。Docker 能帮你省去环境安装,但同时把配置目录、文件存储、进程管理变成黑匣子,出了问题更难判断是容器问题还是 Odoo 本身的问题。先本地裸跑,再把同一套配置迁移到容器,是比较稳妥的路径。
| 对比项 | Odoo 16 | 新版本 |
|---|---|---|
| 社区资料与中文文档 | 多且稳定 | 偏少,英文为主 |
| Python 版本兼容 | 3.8 – 3.10 | 要求更高版本 |
| 第三方模块覆盖 | 绝大多数场景够用 | 还在迁移中 |
| 长期维护周期 | 官方支持期长 | 更依赖最新更新 |
2.2 源码方式安装:最小命令序列
常见做法是在 Ubuntu 22.04 或 Debian 12 上装 Odoo 16,因为系统自带 Python 版本合适,PostgreSQL 安装也简单。我一般会创建一个独立系统用户来跑 Odoo,而不是直接用 root,一是避免文件权限混乱,二是后续用 systemd 托管进程时更安全。下面的命令按顺序执行,每一步都有依赖关系。
# 更新系统包索引,装编译和运行依赖 sudo apt update sudo apt install -y git python3 python3-pip python3-venv \ libpq-dev build-essential wget # 创建独立用户,后面所有 Odoo 相关操作都在这个用户下执行 sudo useradd -m odoo16 # 从官方公开仓库克隆 16.0 分支,--depth 1 只拉取当前快照 sudo -u odoo16 git clone --depth 1 --branch 16.0 \ https://github.com/odoo/odoo.git /home/odoo16/odoo # 创建 Python 虚拟环境,隔离项目依赖 sudo -u odoo16 python3 -m venv /home/odoo16/venv # 安装 Odoo 的 Python 依赖,requirements.txt 由官方维护 sudo -u odoo16 /home/odoo16/venv/bin/pip install -r \ /home/odoo16/odoo/requirements.txt克隆仓库时我特意加了--depth 1,它只保留最新一次提交,克隆体积小、速度快。后面需要升级版本时再git fetch --depth 1即可,对基础篇完全够用。虚拟环境这一步很多人偷懒跳过,直接拿系统 Python 跑,结果装了一堆全局包,后续项目一多就乱。venv 是 Python 开发的基本卫生习惯,Odoo 16 也不例外。
依赖安装完成后,建议先跑一次版本检查确认环境没坏。命令是/home/odoo16/venv/bin/python /home/odoo16/odoo/odoo-bin --version,能正常输出版本号就说明基础依赖没问题。如果报缺少某个模块,不要急着手动 pip 安装,先检查是不是 requirements.txt 没有全部装上,这种报错多半是网络中断导致装到一半。
2.3 数据库就绪:PostgreSQL 用户与权限
Odoo 默认使用当前操作系统的用户名去连接 PostgreSQL,所以给系统用户 odoo16 同名的数据库用户是最省心的配置。开发环境可以给超级权限,生产环境建议只给 createdb 权限,否则 Odoo 初始化时无法建库。先安装 PostgreSQL,再创建用户。
sudo apt install -y postgresql # 创建与系统用户同名的数据库超级用户 sudo su - postgres -c "createuser -s odoo16" # 验证能否以 odoo16 身份连接数据库服务 sudo -u odoo16 psql -l-s表示超级用户,开发阶段省去很多权限排查的麻烦。如果生产环境不想给超级权限,可以用这条命令替代:sudo su - postgres -c "createuser -o odoo16 --createdb",只授予建库和创建角色权限。最终psql -l能列出数据库列表,就说明连接成功。
数据库这里最容易踩的坑是密码问题。Odoo 配置文件里如果不写db_password,它默认用 Unix 本地连接的空密码方式访问 PostgreSQL,这是正常配置,不要手动填一个错误密码进去。如果你非要用密码连接,必须在 PostgreSQL 里先给 odoo16 设置密码,然后两边保持一致,不能只在配置文件里改。
提示:本地开发的数据库操作都用 PostgreSQL 的 peer 认证,Odoo 和数据库跑在同一台机器时,配置里留空
db_password是最稳的做法。
3. 把配置文件写对:Odoo 16 启动前必须懂的参数
3.1 一份能跑的最小配置
Odoo 16 的配置是 ini 格式,默认情况下不写配置也能启动,但那样会把数据库和数据目录放到奇怪的位置,后期很难维护。我建议从第一次启动就固定配置文件,路径我放在/etc/odoo16/odoo16.conf,内容如下。这份配置是一个完整的最小集,每行都有实际作用。
[options] addons_path = /home/odoo16/odoo/addons,/home/odoo16/my-addons data_dir = /home/odoo16/odoo-data db_host = 127.0.0.1 db_port = 5432 db_user = odoo16 db_password = False dbfilter = ^demo16$ web_interface = 127.0.0.1addons_path是模块搜索路径,多个目录用逗号分隔。第一段是官方自带模块目录,第二段是自定义模块目录,路径里必须写绝对路径。data_dir用来存放附件、会话和静态资源缓存,我单独建了/home/odoo16/odoo-data目录,避免和代码目录混在一起。
db_host写成127.0.0.1而不是 localhost,是为了让 Odoo 走 TCP 连接而不是 Unix socket,配合db_password = False时行为更稳定。dbfilter是数据库过滤正则,^demo16$表示该实例只认 demo16 这一个数据库,这个参数在生产环境特别重要,能防止 Odoo 界面里看到并连上服务器上其他不相关的库。
注意:改了配置文件后必须重启 Odoo 进程才会生效。很多人改完配置刷新页面没用,就以为是文件写错了。
3.2 首次启动与数据库初始化
配置文件就绪后,第一次启动要完成数据库初始化。这个步骤会创建数据库结构并写入基础模块,Odoo 16 中基础模块不是选的,而是初始化时默认安装的。下面的命令执行完不会卡在后台,它会初始化完自动退出,方便看到所有日志输出。
sudo -u odoo16 /home/odoo16/venv/bin/python \ /home/odoo16/odoo/odoo-bin \ -c /etc/odoo16/odoo16.conf \ -d demo16 \ --stop-after-init-d demo16指定要初始化的数据库名,如果该数据库不存在会自动创建,前提是配置里的 db_user 有建库权限。--stop-after-init是基础篇必须记住的参数,它让 Odoo 完成初始化后立刻退出,适合安装、升级模块时使用,不会占住终端。
等这条命令运行完,再执行不带--stop-after-init的启动命令。如果一切正常,日志末尾会显示 HTTP 服务在127.0.0.1:8069上监听,浏览器访问这个地址就能看到页面。这里有个易错点:很多人第一次启动直接用sudo -u odoo16跑后台服务,其实基础篇阶段前台运行更好,日志直接打在终端,报错能立刻看到。
3.3 前端资源起不来:样式丢失与日志定位
Odoo 16 的前端资源不是预编译好随代码分发的,web 客户端首次启动时会做静态资源编译。最常见的问题是打开页面后完全没有样式,控制台一堆资源加载失败。遇到这种情况,先看启动日志,再检查 data_dir 的权限。下面的命令把可能钩住的两个点都处理掉。
# 创建数据目录并授权给 odoo16 用户 sudo mkdir -p /home/odoo16/odoo-data sudo chown -R odoo16:odoo16 /home/odoo16/odoo-data # 如果日志提示缺少 less 相关依赖,重新完整安装依赖 sudo -u odoo16 /home/odoo16/venv/bin/pip install -r \ /home/odoo16/odoo/requirements.txt # 查看日志最后 50 行,定位是权限还是资源加载问题 sudo -u odoo16 tail -n 50 /home/odoo16/odoo16.log启动 Odoo 时如果没指定--logfile,日志会直接打在终端。第一次跑通后建议加一个参数把它落到文件里,比如--logfile=/home/odoo16/odoo16.log,排错时不用一直挂着终端。样式丢失的另一个根源是浏览器缓存了旧的静态资源,按 Ctrl+Shift+R 强制刷新通常就能解决,不必急着清数据目录。
日志里如果看到lessc或者node相关报错,说明前端编译环境缺少 node 组件,回到 2.2 节确认系统级的npm有没有装。这类问题网上常有人建议清空 data_dir 重启,但那属于最后手段,清掉的是附件和会话数据,不是代码数据,一定要先确认日志内容再动手。
4. 写第一个自定义模块:Odoo 16 的最小可运行骨架
4.1 模块目录与 manifest 骨架
Odoo 16 的模块就是一个带固定结构的目录,目录名是模块技术名称,只能用小写字母和下划线。新建模块不需要命令行工具,手动建目录就行,结构如下。这个骨架是基础篇最核心的东西,后面所有业务逻辑都是在这个基础上扩展出来的。
my_first_module/ ├── __init__.py ├── __manifest__.py ├── models/ │ ├── __init__.py │ └── my_model.py └── views/ └── my_model_views.xml__manifest__.py是模块的声明文件,告诉 Odoo 这个模块是谁、依赖什么、要加载哪些数据文件。下面的内容是所有 Odoo 16 模块的最小声明,字段名一个都不能拼错,否则安装直接报错。
{ "name": "My First Module", "version": "16.0.1.0.0", "category": "Tools", "summary": "演示最小可运行模块", "depends": ["base"], "data": [ "views/my_model_views.xml", ], "installable": True, "application": True, }depends列表必须包含 base,这是 Odoo 所有模块的基础依赖。data里声明 XML 文件路径,Odoo 安装模块时会按列表顺序加载这些文件。如果后续要加安全权限 CSV,也要加到这里,顺序是先加权限文件,再加视图文件,这个顺序是硬性要求。
4.2 模型定义:一个带名称和描述的表
模型是 Odoo 里处理业务数据的核心,每个模型对应数据库里的一张表。下面定义一个名为my.first.model的模型,模型名用点分隔,Odoo 会自动把它映射成数据库表my_first_model。先写模型文件,再在models/__init__.py里导入。
from odoo import models, fields class MyFirstModel(models.Model): _name = "my.first.model" _description = "我的第一个模型" name = fields.Char(string="名称", required=True) description = fields.Text(string="备注") active = fields.Boolean(string="有效", default=True)name字段不是必须的,但 Odoo 的列表视图和搜索逻辑默认拿它做显示名,所以基础模块里最好带上。active字段是 Odoo 的软删除机制,值为 False 的记录在普通视图里默认不显示,这个字段几乎是所有业务模型的标配。
from . import my_modelmodels/__init__.py必须把新写的模型文件导入,Python 的类才能被 Odoo 注册到模型系统里。很多新手改完my_model.py发现界面看不到新模型,第一反应是代码写错了,实际上八成是忘了在这里加导入。这两个文件写完后,先做一次升级操作再进界面,接下来 4.3 节会说视图,这里先确认模型能建表。
4.3 视图与菜单:XML 数据文件的作用
Odoo 16 的界面是用 XML 数据文件定义的,菜单、动作、视图都是数据库里的记录。下面的 XML 定义一个窗口动作、一个顶级菜单和树状、表单两种视图。最外层标签是<odoo>,里面每条<record>都是一条写入数据库的记录。
<odoo> <record id="action_my_first_model" model="ir.actions.act_window"> <field name="name">我的模型</field> <field name="res_model">my.first.model</field> <field name="view_mode">tree,form</field> </record> <record id="menu_my_first_model" model="ir.ui.menu"> <field name="name">我的模块</field> <field name="sequence">10</field> <field name="action" ref="action_my_first_model"/> </record> <record id="view_my_first_model_tree" model="ir.ui.view"> <field name="name">my.first.model.tree</field> <field name="model">my.first.model</field> <field name="arch" type="xml"> <tree string="我的模型"> <field name="name"/> <field name="active"/> </tree> </field> </record> <record id="view_my_first_model_form" model="ir.ui.view"> <field name="name">my.first.model.form</field> <field name="model">my.first.model</field> <field name="arch" type="xml"> <form string="我的模型"> <sheet> <group> <field name="name"/> <field name="description"/> <field name="active"/> </group> </sheet> </form> </field> </record> </odoo>view_mode里的tree,form表示列表视图优先、表单视图其次。上面这段 XML 里定义了自定义视图,但窗口动作还没绑定它们,所以实际打开的是 Odoo 自动生成的默认视图。要让自定义视图生效,需要在动作里加view_ids配置,基础篇阶段建议先不配,等你看过自动视图长什么样,再回来替换成自己的布局。
这里需要解释一个容易误解的点:独立定义一个视图记录并不会自动替换默认视图,它只是多了一条视图配置。系统在渲染界面时,会按model、type和优先级找到最合适的视图。想让列表页用自定义树状视图,最简单的是等模块装好后,在界面开发者模式里手动调整,或者在本节代码基础上补全view_ids配置。基础篇先把记录建起来、理解record和field的对应关系就足够。
4.4 安装与升级循环:让改动生效的命令式写法
模块写好后,把它放到配置的addons_path里指定的自定义目录,然后执行安装命令。Odoo 16 里安装和升级是两个不同的操作:-i是安装,-u是升级。下面的命令先把模块装进 demo16 数据库。
sudo -u odoo16 /home/odoo16/venv/bin/python \ /home/odoo16/odoo/odoo-bin \ -c /etc/odoo16/odoo16.conf \ -d demo16 \ -i my_first_module \ --stop-after-init看到日志输出module my_first_module: installing就说明模块正在安装。此刻打开浏览器,菜单应该能出现了,但注意如果你还没配权限 CSV,普通操作可能受限,这是第 5 章要解决的问题。安装完成后,后续每次修改 Python 模型或者 XML 视图,都要执行升级而不是重装。
sudo -u odoo16 /home/odoo16/venv/bin/python \ /home/odoo16/odoo/odoo-bin \ -c /etc/odoo16/odoo16.conf \ -d demo16 \ -u my_first_module \ --stop-after-initPython 模型字段改动后必须跑-u,数据库列才会同步创建。XML 视图改动后同样跑-u,视图记录才会被重新加载。如果改了代码不升级,界面没有任何变化,这是 Odoo 开发里最常见的血泪经验之一。我一般会养成习惯:改完代码立刻升级,看到日志末尾没有 ERROR 再切到界面验证。
5. 避坑:Odoo 16 基础实战里的五个高频报错
5.1 安装模块后菜单没出现
现象:-i my_first_module执行成功,日志没有报错,但登录界面后整个侧边栏都找不到新菜单。
原因:最常见的是模型没有权限记录。Odoo 里新建模型后,默认任何用户都没有读写权限,界面里即使有菜单和动作,点击后也会报权限错误或者干脆不显示。第二个常见原因是菜单记录没有配父级菜单,顶栏里不会自动出现。
解决:在模块里加一个权限文件security/ir.model.access.csv,然后把它加进 manifest 的data。这是唯一标准的解决办法。
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_my_first_model_all,my.first.model.all,model_my_first_model,,1,1,1,1model_id:id写model_my_first_model,这是 Odoo 根据模型自动生成的外部标识。group_id:id留空表示所有人可用。加完文件后重新升级模块,菜单才能正常使用。
5.2 改了模型字段,数据库没有新列
现象:在my_model.py里新增了一个字段,升级模块后进入界面,系统报字段不存在或者数据库查询出错。
原因:改完 Python 模型没有执行-u升级,或者升级时数据库连接配置不对导致建列失败。Odoo 不会在你修改代码后自动同步数据库表结构,它只在升级模块时对比模型定义和实际表结构。
解决:执行 4.4 节的升级命令。升级过程中日志会把每个模型的字段变更打出来,如果没有看到你的新字段,说明模块路径不对,检查addons_path和模块目录名是否一致。
注意:有些开发者图省事直接重启服务,不升级模块,这样永远不会生效。在 Odoo 16 里,改 Python 模型字段后,"重启服务 + 刷新页面"是错误的调试路径。
5.3 视图报错:Field "xxx" not found
现象:升级模块时直接报错Field "description" does not exist,或者类似的字段不存在错误,模块无法完成安装。
原因:XML 视图里写了模型没有的字段名称,或者模型类没有被正确导入,Odoo 在加载视图时找不到对应的字段定义。
解决:先把 XML 里所有field标签的name属性,和模型文件里的字段定义逐行对照。再看一眼models/__init__.py有没有把模型模块 import 进来。最后确认depends里包含 base,如果视图里引用了其他模块的模型,还要在 manifests 里加对应依赖。这个报错是新手最容易怕的类型,其实排查路径非常固定:字段名 → import → 依赖。
5.4 addons_path 只写了一个路径,自己模块永远不可见
现象:在浏览器应用列表里找不到my_first_module,安装模块下拉列表为空或者只有系统自带模块。
原因:配置文件里的addons_path只写了官方模块目录/home/odoo16/odoo/addons,自定义模块目录没有加入。Odoo 不会自动递归扫描其他位置的模块。
解决:确保配置里用逗号同时列出两个路径,并重启服务。这是修改配置文件后必须做的一步,重启 Odoo 进程重新读取配置,再进应用列表搜索模块。
addons_path = /home/odoo16/odoo/addons,/home/odoo16/my-addons这里有个排查技巧:启动 Odoo 时加--log-level=debug,日志里会输出所有已加载模块的列表。如果自定义目录下的模块没出现,检查模块目录下有没有__manifest__.py,以及该文件是否能被 Python 正常解析,json格式错误会导致整个模块被静默跳过。
5.5 前端资源错乱:没有样式,部分按钮不断加载
现象:页面能打开但完全没有 CSS 样式,列表页和表单页布局混乱,一些按钮点击后一直转圈没有响应。
原因:data_dir 里的静态资源缓存损坏或不完整,或者数据目录权限不足,Odoo 无法正常生成前端资源。这类问题在反复重启、物理机断电后较容易出现。
解决:第一步确认 data_dir 归属用户是 odoo16。第二步清理残旧资源,这是基础篇阶段最直接的方法,只在开发环境做,生产环境要谨慎清数据。
sudo -u odoo16 rm -rf /home/odoo16/odoo-data/filestore sudo -u odoo16 rm -rf /home/odoo16/odoo-data/sessions清理后重启 Odoo,让它重新生成全部静态资源。如果你部署的实例已经跑了一段时间,里面可能有上传附件,清掉 filestore 会丢失这些文件,所以这个操作只适合本地开发库。先排查日志和权限,不要一上来就清数据目录,这样容易把没有问题的附件也一起误删。
6. 用调试与数据复位把 Odoo 16 开发节奏拉起来
6.1 日志内联与 debug 模式
基础篇后期,你应该把启动命令固定成带日志文件的写法,日志是 Odoo 16 排错的第一信息来源。下面这条命令会输出比默认更详细的日志,包括 SQL 查询和视图加载过程,遇到权限和字段问题时比猜代码高效得多。
sudo -u odoo16 /home/odoo16/venv/bin/python \ /home/odoo16/odoo/odoo-bin \ -c /etc/odoo16/odoo16.conf \ -d demo16 \ --logfile=/home/odoo16/odoo16.log \ --log-level=debug--log-level=debug会输出大量细节,生产环境不建议开,本地开发时开起来能让很多隐蔽问题现形。浏览器端还有一个技巧:把登录地址换成http://127.0.0.1:8069/web?debug=1,页面右上角会多出调试菜单,可以直接查看视图层级和模型字段,特别适合对照 XML 检查界面结构。
6.2 用测试文件验证字段约束
基础篇的模块还没有复杂逻辑,但可以把验证方式提前养成测试习惯。在模块下建tests/__init__.py和tests/test_my_model.py,写一个最小测试用例,检查模型创建和必填字段约束。
from odoo.tests import Common class TestMyModel(Common): def test_name_create(self): rec = self.env["my.first.model"].create({"name": "demo"}) self.assertEqual(rec.name, "demo")运行测试用下面的命令,--test-tags指定模块名,只跑当前模块的测试,不会把整个库的测试全部跑一遍。
sudo -u odoo16 /home/odoo16/venv/bin/python \ /home/odoo16/odoo/odoo-bin \ -c /etc/odoo16/odoo16.conf \ -d demo16 \ --test-enable \ --test-tags my_first_module \ --stop-after-init输出里出现Tests: 1就说明测试生效了。我自己的经验是:测试不一定要覆盖所有逻辑,但至少把创建、读取、字段约束这类基础路径守住。这样每次改完模型跑一次测试,比反复手工点界面确认要踏实得多。
6.3 数据复位:删库重建而不是清数据库
开发和调试到后期,demo16 库里会堆积大量实验数据,继续在这个库里升级模块可能产生各种奇怪残留。最干净的复位方法是直接把数据库删掉重建,再初始化一次。这个习惯能避免很多玄学问题,库是全新结构,所有模块都是重新安装,状态可控。
sudo -u postgres dropdb demo16 sudo -u postgres createdb demo16 -O odoo16重建后执行第 3 章的初始化命令,然后重新安装模块。整个过程一分钟不到,换来的是一个完全干净的验证环境。我早期在同一个库里反复升级,遇到字段残留问题经常要翻旧账,后来改成“先 dropdb 再重来”,反而省下大量时间。Odoo 16 基础阶段的代码量不大,删库重建没有任何心理负担,等真正进入业务数据阶段,再来考虑数据库迁移和备份方案。
希望这篇笔记能帮你把 Odoo 16 的入门路径走成一条明确可复现的链路,不靠运气跑通,也不在排错上反复徘徊。
本文还有配套的精品资源,点击获取