全书完整目录请见:Odoo 14开发者指南(Cookbook)第四版
在第一章 安装Odoo开发环境中,我们学习了如何使用源码中所带的标准核心插件配置Odoo实例。本章主要讲解如何对Odoo实例添加非核心或自定义插件。在Odoo中,可以通过多个目录加载插件。此外,推荐使用单独的目录加载第三方插件或自定义的插件,以避免与Odoo核心模块产生冲突。甚至Odoo企业版也是一种类型的插件目录,需要像加载普通插件目录那样对其进行加载。
本章中,我们将讲解如下内容:
- 配置插件路径
- 标准化你的实例目录布局
- 安装及升级本地插件模块
- 通过GitHub安装插件模块
- 对插件应用修改
- 应用及尝试建议的拉取请求
📝有关用语
本书中,我们会交叉使用插件(add-on)、模块(module)、应用(app)或插件模块(add-on module)。它们都是指可通过用户界面在Odoo中安装的Odoo应用或扩展应用。
配置插件路径
通过addons_path参数的配置,可以在 Odoo 中加载自己的插件模块。在Odoo初始化一个新数据库时,它会在addons_path配置参数中给定的这些目录中搜索插件模块。addons_path会在这些目录中搜索潜在的插件模块。
addons_path中所列出的目录预期应包含子目录,每个子目录是一个插件模块。在数据库初始化完成后,将能够安装这些目录中所给出的模块。
准备工作
这一部分假定你已经准备好了实例并生成了配置文件,如在第一章 安装Odoo开发环境在一个文件中存储实例配置一节所描述。Odoo的源码存放在~/odoo-dev/odoo中,而配置文件存放在~/odoo-dev/myodoo.cfg中。
如何配置…
按如下步骤在实例的addons_path中添加~/odoo-dev/local-addons目录:
- 编辑你的实例配置文件,即 ~/odoo-dev/myodoo.cfg。
- 定位到以addons_path =开头的一行,默认应该会看到如下内容:
1addons_path = ~/odoo-dev/odoo/addons
译者注:当前默认生成的配置文件中为绝对路径 - 修改该行,添加一个逗号(英文半角),并接你想要添加为addons_path的目录名称,如以下代码所示:
1addons_path = ~/odoo-dev/odoo/addons,~/odoo-dev/local-addons - 在终端中重启实例
1$ ~/odoo-dev/odoo/odoo-bin -c my-instance.cfg
运行原理…
在重启 Odoo 时,会读取配置文件。addons_path变量的值应为一个逗号分隔的目录列表。可接受相对路径,但它们是相对于当前工作目录的,因此应在配置文件中尽量避免。
至此,我们仅在Odoo中列出了插件目录,但~/odoo-dev/local-addons中尚不存在插件模块。即使在该目录中新增了插件模块,Odoo也不会在用户界面中显示这一模块。为此,你需要执行一个额外的操作,在下一部分更新插件模块列表中会进行讲解。
📝这背后的原因是在初始化新数据库时,Odoo在可用模块中自动列举了自定义模块,但如若在数据库初始化之后新增模块,就需要像更新插件模块列表一节中那样手动更新可用模块列表。
扩展知识…
在首次调用 odoo-bin脚本来初始化新数据库时,可以传递一个带逗号分隔目录列表的–addons-path命令行参数。这会以所提供插件路径中所找到的所有插件来初始化可用插件模块列表。这么做时,要显式地包含基础插件目录(odoo/odoo/addons)以及核心插件目录(odoo/addons)。与前面稍有不同的是本地插件目录不能为空(译者注:请先阅读下面的小贴士),它必须要至少包含一个子目录,并包含插件模块的最小化结构。
在第三章 创建Odoo插件模块中,我们会来看如何编写你自己的模块。同时,这里有一个生成内容来满足Odoo要求的快捷版黑科技:
1 2 3 4 |
$ mkdir -p ~/odoo-dev/local-addons/dummy $ touch ~/odoo-dev/local-addons/dummy/__init__.py $ echo '{"name": "dummy", "installable": False}' > \ ~/odoo-dev/local-addons/dummy/__manifest__.py |
你可以使用–save选项来保存路径至配置文件中:
1 2 3 |
$ odoo/odoo-bin -d mydatabase \ --addons-path="odoo/odoo/addons,odoo/addons,~/odoo-dev/local-addons" \ --save -c ~/odoo-dev/my-instance.cfg --stop-after-init |
本例中,使用相对路径不会有问题,因为它们会在配置文件中转化为绝对路径。
📝注:因为Odoo仅当从命令行中设置路径时在插件路径的目录中查看插件,而不是在从配置文件中加载路径的时候,dummy已不再必要。因此,你可以删除它(或保留到你确定不需要新建一个配置文件时)。
标准化你的实例目录布局
我们推荐你在开发和生产环境都使用相似的目录布局。这一标准化会在你要执行运维时体现出用处,它也会缓解你日常工作的压力。
这一部分创建将相似生命周期或相似用途的文件分组放在标准化子目录中的目录结构。
📝仅在希望以相似的文件结构管理开发和生产环境时才需要学习本节。如果不需要,可以跳过本节。
此外,不必严格按照本节中相同的目录结构。请自由按照自己的需求来调整这一结构。
如何标准化…
创建所推荐实例布局,需要执行如下步骤:
- 为每个实例创建一个目录:
12$ mkdir ~/odoo-dev/projectname$ cd ~/odoo-dev/projectname - 在名为env/的子目录中创建一个Python虚拟环境对象:
1$ python3 -m venv env - 创建一些子目录,如下:
1$ mkdir src local bin filestore logs
这些子目录的功能如下:- src/:包含Odoo本身的一个拷贝,以及一些第三方插件项目(我们在下一步中添加了Odoo源码)
- local/:用于保存你针对具体实例的插件
- bin/:包含各类帮助可执行shell脚本
- filestore/:用于文件存储
- logs/(可选):用于存储服务日志文件
- 克隆Odoo并安装所需依赖包(参见第一章 安装Odoo开发环境获取更多内容):
12$ git clone -b 14.0 --single-branch --depth 1 https://github.com/odoo/odoo.git src/odoo$ env/bin/pip3 install -r src/odoo/requirements.txt - 以bin/odoo保存如下shell脚本:
123456#!/bin/shROOT=$(dirname $0)/..PYTHON=$ROOT/env/bin/python3ODOO=$ROOT/src/odoo/odoo-bin$PYTHON $ODOO -c $ROOT/projectname.cfg "$@"exit $? - 让该脚本可执行:
1$ chmod +x bin/odoo - 创建一个空的本地模块dummy:
1234$ mkdir -p local/dummy$ touch local/dummy/__init__.py$ echo '{"name": "dummy", "installable": False}' >\local/dummy/__manifest__.py - 为你的实例生成配置文件:
123$ bin/odoo --stop-after-init --save \--addons-path src/odoo/odoo/addons,src/odoo/addons,local \--data-dir filestore - 添加一个.gitignore文件,用于告诉GitHub排除这些给定目录,这样Git在提交代码时就会忽略掉这些目录,例如 filestore/, env/, logs/和src/:
123456789101112# dotfiles, with exceptions:.*!.gitignore# python compiled files*.py[co]# emacs backup files*~# not tracked subdirectories/env//src//filestore//logs/ - 为这个实例创建一个Git仓库并将已添加的文件添加到Git中:
123$ git init$ git add .$ git commit -m "initial version of projectname"
运行原理…
我们生成了一个有明确标签目录和独立角色的干净目录结构。我们使用了不同的目录来存储如下内容:
- 由其它人所维护的代码(src/中)
- 本地相关的具体代码
- 实例的文件存储(filestore)
通过为每个项目建一个virtualenv环境,我们可以确保该项目的依赖文件不会与其它项目的依赖产生冲突,这些项目你可能运行着不同的Odoo版本或使用了不同的第三方插件模块,这将需要不同版本的Python依赖。当然也会带来一部分磁盘空间的开销。
以类似的方式,通过为我们不同的项目使用不同的Odoo拷贝以及第三方插件模块,我们可以让每个项目单独的进行演化并仅在需要时在这些实例上安装更新,因此也减少了引入回退的风险。
bin/odoo允许我们不用记住各个路径或激活虚拟环境就可以运行服务。这还为我们设置了配置文件。你可以在其中添加其它脚本来协助日常工作。例如,可以添加一个脚本来检查运行实例所需的第三方项目。
有关配置文件,我们仅展示了这里需要设置的最小化选项,但很明显可以做更多设置,例如数据库名、数据库过滤器或项目所监听的端口。有关这一话题的更多信息,请参见第一章 安装Odoo开发环境。
最后,通过在Git仓库中管理所有这些,在不同的电脑上复制这一设置及在团队中分享开发内容变得相当容易。
📝加速贴士
要加速项目的创建,可以创建一个包含空结构的模板仓库,并为每个新项目复制(fork)该仓库。这会省却你重新输入bin/odoo脚本、.gitignore及其它所需模板文件(持续集成配置、README.md、ChangeLog等等)所花费的时间。
参见内容
如果你喜欢这种方法,我们建议你尝试第三章 服务器部署中的使用 Docker 运行 Odoo 一部分的内容。
扩展知识…
复杂模块的开发要求有各类配置选项,在想要尝试任何配置选项时都会要更新配置文件。更新配置文件常常是一件头痛的事,避免它的一种方式是通过命令行传递所有配置选项,如下:
- 手动激活虚拟环境:
1$ source env/bin/activate - 进入Odoo源代码目录:
1$ cd src/odoo - 运行服务:
1./odoo-bin --addons-path=addons,../../local -d test-14 -i account,sale,purchase --log-level=debug
第3步中,我们直接通过命令行传递了一些参数。第一个是–addons-path,它加载Odoo的核心插件目录addons,以及你自己的插件目录local,在其中你可以放自己的插件模块。选项-d会使用test-14数据库或者在该数据库不存在时新建一个数据库。选项-i 会安装会计、销售和采购模块。接着,我们传递了log-level选项来将日志级别提升为debug,这样日志中会显示更多的信息。
📝通过使用命令行,你可以快速地修改配置选项。也可以在Terminal中查看实时日志。所有可用选项可参见第一章 安装Odoo开发环境,或使用-help命令来查看所有的选项及各个选项的描述。
安装并升级本地插件模块
Odoo 功能的核心来自于它的插件模块。Odoo自带的插件是你所拥有的财富,同时你也可以从应用商店下载一些插件模块或者自己写插件。
这一节中,我们将展示如何通过网页界面及命令行来安装和升级插件模块。
对这些操作使用命令行的主要好处有可以同时作用于一个以上的插件以及在安装或升级的过程中可以清晰地浏览到服务端日志,对于开发模式或编写脚本安装实例时都非常有用。
准备工作
确保你有一个运行中的 Odoo 实例,且数据库已初始化、插件路径已进行恰当地设置。在这一部分中,我们将安装/升级一些插件模块。
如何安装升级…
安装或升级插件有两种方法-可以使用网页界面或命令行。
通过网页界面
可按照如下步骤来使用网页界面安装新的插件模块到数据库中:
- 使用管理员账户连接实例并打开Apps菜单
图2.1 – Odoo应用列表 - 使用搜索框来定位你想要安装的插件。这里有一些帮助你完成该任务的操作指南:
- 激活Not Installed过滤器
- 如果你要查找一个具体的功能插件而不是广泛的功能插件,删除Apps过滤器
- 在搜索框中输入模块名的一部分并使用它来作为模块过滤器
- 你会发现使用列表视图可以阅读到更多的信息
- 点击卡片中模块名下的Install按钮。
注意有些Odoo插件模块具有外部Python依赖,如果你的系统中未安装该Python依赖,那么 Odoo 会中止安装并显示如下的对话框:
图2.2 – 外部库依赖的警告
译者注:按正常安装不会出现一错误,需通过 pip uninstall pyldap 才能复现这一错误
修复这一问题,仅需在你的系统中安装相关的Python依赖即可。
要升级已安装到数据库的模块,使用如下步骤:
- 使用管理员账户连接到实例
- 打开Apps菜单
- 点击Apps:
图2.3 – Odoo应用列表 - 使用搜索框来定位你所安装的插件。有如下的小贴士:
- 激活Installed过滤器
- 如果你要查找一个具体的功能插件而不是广义的功能插件,删除Apps过滤器
- 在搜索框中输入部分插件模块的名称并按下 Enter 来使用它作为模块过滤器。例如,输入CRM并按下 Enter 来搜索CRM应用
- 你会发现使用列表视图可以阅读到更多的信息
- 点击卡片右上角的的三个点,然后点击Upgrade选项:
图2.4 – 升级模块的下拉链接
激活开发者模式来查看模块的技术名称。如果你不知道如何激活开发者模式,请参见第一章 安装Odoo开发环境:
图2.5 – 应用的技术名称
在激活开发者模式之后,它会以红色显示模块的技术名称。如果你使用的是Odoo社区版,会看到一些带有Upgrade按钮的应用。这些是Odoo企业版的应用,要想安装/使用它们,需要购买一个证书。
通过命令行
在数据库中安装新插件,可执行如下步骤:
- 查找插件的名称。这是包含__manifest__.py文件的目录名,不带前面的路径。
- 停止实例。如果你在操作生产数据库,请进行备份。
- 运行如下命令:
1$ odoo/odoo-bin -c instance.cfg -d dbname -i addon1,addon2 --stop-after-init
如果在配置文件中进行过设置可以省略掉-d dbname。
译者注:请将addon1,addon2替换为你所要安装的插件名 - 重启实例
升级数据库中已安装的插件,可执行如下步骤:
- 查找待更新的插件模块名称。这是包含__manifest__.py文件的目录名,不带前面的路径。
- 停止实例。如果你在操作生产数据库,请进行备份。
- 运行如下命令:
1$ odoo/odoo-bin -c instance.cfg -d dbname - u addon1 --stop-after-init
如果在配置文件中进行过设置可以省略掉-d dbname。 - 重启实例
运行原理…
插件模块的安装和升级是两个紧密关联的操作,但有一些重要的区别,在下面两部分中进行了强调:
插件安装
在安装插件时,Odoo以提供的名称检查它的可用插件列表中未安装插件。它还会检查该插件的依赖,并且如果有依赖的话,它会在安装插件前递归安装这些依赖。
单个模块的安装包含如下步骤:
- 如果存在,运行插件preinit钩子
- 从Python源代码中加载模型定义并在必要时更新数据库结构(参见第四章 应用模型了解更多信息)
- 加载插件的数据文件并在必要时更新数据库内容(参见第六章 管理模块数据了解更多信息)
- 如果实例中启用了演示数据则安装插件演示数据
- 如果存在,运行插件postinit钩子
- 运行对插件视图定义的验证
- 如果启用了演示数据及测试,运行该插件的测试(参见第十八章 自动化测试用例了解更多信息)
- 在数据库中更新模块状态
- 从插件的翻译文件中更新数据库中的翻译(参见第十一章 国际化了解更多信息)
📝preinit和postinit钩子分别使用pre_init_hook和post_init_hook键名在__manifest__.py文件中定义。这些钩子用于在插件模块的安装之前及之后触发Python函数。参见第三章 创建Odoo插件模块了解更多有关 init 钩子的知识。
插件升级
升级插件时,Odoo以给定的名称在可用的插件模块列表中检查已安装插件。它还会检查该插件的反向依赖(即依赖于所升级插件的那些插件)。如果存在,则也会对它们进行递归升级。
单个插件模块的升级过程包含如下步骤:
- 如果存在,先运行插件模块的预迁移步骤(参见第六章 管理模块数据了解更多信息)
- 从Python源码中加载模型定义并在必要时更新数据库结构(参见第四章 应用模型了解更多信息)
- 加载插件的数据文件并在必要时更新数据库内容(参见第六章 管理模块数据了解更多信息)
- 如果实例中启用了演示数据更新插件演示数据
- 如果模块有任何迁移方法的话,运行插件模块的后置迁移步骤(参见第六章 管理模块数据了解更多信息)
- 运行对插件视图定义的验证
- 如果启用了演示数据并启用了测试,运行该插件的测试(参见第十八章 自动化测试用例了解更多信息)
- 在数据库中更新模块状态
- 从插件的翻译文件中更新数据库中的翻译(参见第十一章 国际化了解更多信息)
📝注意更新未安装的插件模块时什么也不会做。但是安装已安装的插件模块会重新安装该插件,这会通过一些包含数据的数据文件产生一些预期外的问题,这些文件应由用户进行更新而非在常规的模块升级处理时进行更新(参见第六章 管理模块数据中使用noupdate和forcecreate标记部分的内容)。通过用户界面不存在错误的风险,但通过命令行时则有可能发生。
扩展知识…
要当心依赖的处理。假定有一个实例你想要对其安装sale、sale_stock和sale_specific插件,sale_specific依赖于sale_stock,而sale_stock依赖于sale。要安装这三者,你只需要安装sale_specific,因为它会递归安装sale_stock和sale这两个依赖。要升级这三者,需要升级sale,因为这样会递归升级其反向依赖,sale_stock和sale_specific。
管理依赖另一个比较搞的地方是在你向已经安装了一个版本的插件添加依赖的时候。我们继续通过前例来理解这一问题。想像一下在sale_specific中添加了一个对stock_dropshipping的依赖。更新sale_specific插件不会自动安装新的依赖,也不会要求安装sale_specific。在这种情况下,你会收到非常糟糕的错误消息,因为插件的Python代码没有成功加载,而插件的数据和模型表则已存在于数据库中。要解决这一问题,你需要停止该实例并手动安装新的依赖。
从GitHub安装插件模块
GitHub是第三方插件一个很好的来源。很多Odoo合作伙伴使用GitHub来分享他们内部维护的插件,而Odoo社区联盟(OCA)在GitHub上共同维护着几百个插件。在你开始编写自己的插件之前,确保查看是否已有可直接使用的插件或者作为初始以继续扩展的插件。
这一部分向你展示如何从GitHub上克隆OCA的partner-contact项目并让其中所包含的插件模块在我们实例中可用。
准备工作
假设你希望对客户(partner) 表单添加新的字段。默认Odoo客户模型不包含gender字段。如果要添加gender字段,需要新建一个模块。所幸邮件列表中有人告诉你有partner_contact_gender这么一个插件模块,由OCA作为partner-contact项目的一部分进行维护。
本部分中所使用的路径反映了我们在标准化你的实例目录布局一节中所推荐的布局。
如何安装…
按照如下步骤来安装partner_contact_gender:
- 进入项目目录:
1$ cd ~/odoo-dev/my-odoo/src - 在src/目录中克隆partner-contact项目的14.0分支:
12$ git clone --branch 14.0 \https://github.com/OCA/partner-contact.git src/partner-contact - 修改插件路径来包含该目录并更新你的实例中的插件列表(参见本章中的配置插件路径和更新插件模块列表小节)。instance.cfg中的addons_path一行应该是这样的:
1234addons_path = ~/odoo-dev/my-odoo/src/odoo/odoo/addons, \~/odoo-dev/my-odoo/src/odoo/addons, \~/odoo-dev/my-odoo/src/, \~/odoo-dev/local-addons - 安装partner_contact_gender插件(如果你不知道如何安装该模块,参见前面的小节,安装并升级本地插件模块)
运行原理…
Odoo社区联盟的所有代码仓库都将他们自己的插件放在单独的子目录中,这与Odoo对插件路径中目录的要求是一致的。因此,只需复制某处的仓库并将其添加到插件路径中就够了。
扩展知识…
有些维护者遵循不同的方法,每个插件模块一个仓库,放在仓库的根目录下。这种情况下,需要新建一个目录,在这个目录中添加插件路径并克隆所需维护者的插件到该目录中。记住在每次添加一个新仓库克隆时要更新插件模块列表。
对插件应用修改
GitHub上可用的大部分插件需要进行修改并且不遵循Odoo对其稳定发行版所强制的规则。它们可能进行漏洞修复或改善,包含你提交的问题或功能请求,这些修改可能会带来数据库模式的修改或数据文件和视图中的更新。这一部分讲解如何安装升级后的版本。
准备工作
假定你对partner_contact_gender报告了一个问题并收到通知说该问题已在partner-contact项目14.0分支的最近一次修订中得以解决。这种情况下,你可以使用最新版本来更新实例。
如何修改…
要对来自GitHub的插件进行源的变更,需执行如下步骤:
- 停止使用该插件的实例。
- 如果是生产实例请进行备份(参见第一章 安装Odoo开发环境中管理Odoo服务端数据库一节)。
- 进入克隆了partner-contact的目录:
1$ cd ~/odoo-dev/my-odoo/src/partner-contact - 为该项目创建一个本地标签,这样万一出现了崩溃还可以进行回退:
12$ git checkout 14.0$ git tag 14.0-before-update-$(date --iso) - 获取源码的最新版本:
1$ git pull --ff-only - 在数据库中更新partner_contact_gender插件(参见安装并升级本地插件模块一节)
- 重启实例
运行原理…
通常,插件模块的开发者不时会发布插件的最新版本。这一更新一般包含漏洞修复及新功能。这里,我们将获取一个插件的新版本并在我们的实例中更新它。
如果git pull –ff-only失败的话,可以使用如下命令回退到前一个版本:
1 |
$ git reset --hard 14.0-before-update-$(date --iso) |
然后,可以尝试git pull(不添加–ff-only),它会产生一个合并,但这表示你对插件做了本地修改。
其它内容…
如果更新这一步崩溃了,参见第一章 安装Odoo开发环境从源码更新Odoo一节获取恢复的操作指南。记住要保持首先在生产数据库的拷贝上进行测试。
应用及尝试建议的拉取请求
在GitHub的世界中,拉取请求(PR)是由开发者所提交的请求,这样项目维护人员可以添加一些新的开发。比如一个 PR 可能包含漏洞修复或新功能。这些请求在拉取到主分支之前会进行审核和测试。
这一部分讲解如何对你的 Odoo 项目应用一个PR来测试漏洞修复的改进。
准备工作
在前一节中,假定你对partner_contact_gender 报告了一个问题并收到一条通知在拉取请求中问题已修复,尚未合并到项目的14.0分支中。开发人员要求你验证PR #123中的修复状况。你需要使用这一分支更新一个测试实例。
不应在生产数据库直接使用该分支,因此先创建一个带有生产数据库拷贝的测试环境(参见第一章 安装Odoo开发环境)。
如何操作…
应用并测试一个插件的GitHub拉取请求,需要执行如下步骤:
- 停止实例
- 进入partner-contact所被克隆的目录:
1$ cd ~/odoo-dev/my-odoo/src/partner-contact - 为该项目创建一个本地标签,这样万一出现崩溃时你可以回退:
12$ git checkout 14.0$ git tag 14.0-before-update-$(date --iso) - 拉取pull请求的分支。这么做最容易的方式是使用PR编号,在开发者与你沟通时你应该可以看到。在本例中,这个拉取请求编号是123:
1$ git pull origin pull/123/head - 在你的数据库中更新partner_contact_gender1插件模块并重启该实例(如果你不知道如何更新该模块的话请参见安装并升级本地插件模块一节)
- 测试该更新 – 尝试重现问题,或测试你想要的功能。
如果这不能运行,在GitHub的PR页面进行评论,说明你做了什么以及什么不能运行,这样开发者可以更新这个拉取请求。
如果它没有问题,也在PR页面说下;这是PR验证流程中非常重要的一部分;这会加速主分支中的合并。
运行原理…
我们在使用一个GitHub功能,使用pull/nnnn/head分支名称来通过编号进行拉取请求的拉取,其中nnnn是PR的编号。Git pull命令会合并远程分支到我们的分支,在我们基础代码中应用修改。在这之后,我们更新插件模块、对其测试并向作者报告修改是成功或是失败。
扩展知识…
如果你想要同步测试它们,你可以针对相同仓库的不同拉取请求重复本节中的第4步。如果你对结果很满意,可以创建一个分支来保留对应用了改变的结果的引用:
1 |
$ git checkout -b 14.0-custom |
使用一个不同的分支会有助于记住你没有使用GitHub的版本,而是一个自定义的版本。
📝git branch命令可用于列出你仓库中的所有本地分支。
从这开始,如果需要应用来自GitHub中14.0分支的最近一个审核版本,需要在拉取时不使用–ff-only:
1 |
$ git pull origin 14.0 |