现在我们已经有了开发环境,并且知道如何管理Odoo服务端实例和数据库,接下来学习如何创建Odoo的插件模块。
本章的主要目标是掌握插件模块的结构以及添加组件的典型增量工作流程。本章中提到的各种组件将在后续章节中详细介绍。
一个Odoo模块可以包含多个元素:
- 业务对象:
声明为Python类,这些资源根据其配置由Odoo自动持久化。 - 对象视图:
业务对象UI显示的定义。 - 数据文件(声明模型元数据的XML或CSV文件):
- 视图或报告
- 配置数据(模块参数化和安全规则)
- 演示数据等
- Web控制器:
- 处理来自Web浏览器的请求、静态Web数据图像,或Web界面或网站使用的CSS或JavaScript文件。
本章中,我们将介绍以下内容:
- 创建和安装一个新插件模块
- 完成插件模块的声明
- 组织插件模块的文件结构
- 添加模型
- 添加菜单项和视图
- 添加访问安全
- 使用scaffold命令创建模块
技术要求
学习本章,读者需要安装好Odoo,并且已经完成了第一章 安装Odoo开发环境中各节。还应熟悉如何发现和安装额外的插件模块,可参照第二章 管理Odoo服务端实例。
本章中使用的所有代码可以从GitHub仓库下载,地址是:https://github.com/alanhou/odoo-cookbook/tree/main/Chapter03。
什么是Odoo插件模块?
除框架代码外,Odoo的所有代码库都以模块形式组织。这些模块可以随时从数据库中安装或卸载。这些模块有两个主要目的:可以添加新的应用程序/业务逻辑,或者修改现有的应用程序。简单来说,在Odoo中,一切都始于模块,也终于模块。
Odoo提供各种业务解决方案,如销售、采购、POS、会计、制造、项目和库存。新建模块涉及为业务添加新功能或升级现有功能。
最新版本的Odoo在社区版和企业版中引入了众多新模块,包括会议室、待办事项以及几个WhatsApp相关的集成模块。
此外,该版本还带来了令人兴奋的新功能,如重新设计的用户界面、改进的搜索功能以及CRM、制造和电子商务的新功能。新版本还包括其他改进,如增强的性能、提升的安全性和更多的集成。
Odoo由各种规模的公司使用;每个公司都有不同的业务流程和需求。为解决这个问题,Odoo将应用程序的功能分成不同的模块。这些模块可以按需加载到数据库中。基本上,管理员可以随时启用/禁用这些功能。因此,同一软件可以根据不同的需求进行调整。查看下面的Odoo模块截图;列中的第一个模块是主应用程序,其他模块是为该应用程序添加额外功能而设计的。要获取按应用程序类别分组的模块列表,请访问Apps菜单并按类别分组:
图3.1 – 按类别分组的应用程序
如果你计划在Odoo中开发一个新应用程序,应该为各种功能设置边界。这将非常有助于将应用程序分成不同的插件模块。既然读者已经了解了Odoo插件模块的目的,就可以开始构建我们自己的模块了。
创建和安装一个新插件模块
本例中,我们将新建一个模块,可用于我们的Odoo实例中,并进行安装。
准备工作
首先,我们需要一个Odoo实例。
如果按照第一章 安装Odoo开发环境中的从源码轻松安装Odoo小节的步骤操作,Odoo应该位于~/odoo-dev/odoo
目录中。为方便解释,我们将假设Odoo位于这个位置,当然也可以使用你喜欢的其他位置。
我们还需要添加我们自己Odoo模块的位置。为本例我们将使用odoo
目录同级的local-addons
目录,即~/odoo-dev/local-addons
。
可以将你自己的Odoo模块上传到GitHub并克隆到本地系统进行开发。
操作步骤
例如,在本章中,我们将创建一个小型的插件模块来管理公寓。
按以下步骤创建并安装一个新的插件模块:
- 切换工作目录,并创建一个放置自定义模块的目录:
12$ cd ~/odoo-dev$ mkdir local-addons - 为新模块选择技术名称,并创建目录。本例,我们将使用
my_hostel
:
1$ mkdir local-addons/my_hostel
模块的技术名称必须是有效的Python标识符。它必须以字母开头,并且只能包含字母、数字和下划线字符。模块名称最好只使用小写字母。 - 通过添加
__init__.py
文件使Python模块可导入:
1$ touch local-addons/my_hostel/__init__.py - 添加一个最小的模块声明,以便Odoo可以将其检测为插件模块。在
my_hostel
文件夹中创建一个__manifest__.py
文件,并写入以下内容:
1{'name': 'Hostel Management'} - 启动Odoo实例,并将模块目录添加到插件路径中:
1$ odoo/odoo-bin --addons-path=odoo/addons/,local-addons/
如果在Odoo命令中添加了--save
选项,插件路径将被保存到配置文件中。下次启动服务器时,如果没有提供插件路径选项,将使用这个路径。 - 在Odoo实例中启用新模块。使用admin账号登录Odoo,在About对话框中启用开发者模式,在顶部Apps菜单中选择更新应用列表。此时,Odoo应该识别到了我们的Odoo模块:
图3.2 – 更新应用列表的对话框 - 在顶部选择Apps菜单,在右上角的搜索栏中删除默认的应用过滤器并搜索
my_hostel
。点击Activate按钮,完成安装。
工作原理
Odoo模块是一个包含代码文件和其他资源的目录。使用的目录名称是模块的技术名称。模块声明中的name
键是它的标题。
__manifest__.py
文件是模块声明。包含一个Python字典,里面有模块元数据,包括类别、版本、依赖的模块以及加载的数据文件列表。还包含有关插件模块的重要元数据,并声明应加载的数据文件。
本节中,我们使用了一个最小的声明文件,但在实际模块中,我们还需要其他重要的字段。在下一节完成插件模块的声明中讨论。
模块目录必须是Python可导入的,因此还需要一个__init__.py
文件,空的也行。要加载模块,Odoo服务器中会进行导入。这将执行__init__.py
文件中的代码,因此它充当了运行模块Python代码的入口。因此,通常包含导入语句来加载模块Python文件和子模块。
已知的模块可以直接使用--init
或-i
选项从命令行安装。例如,如果想安装my_hostel
应用程序,可以使用-i my_hostel
。在新建数据库时,这个列表最初会在当时提供的插件路径中找到的模块。可以使用更新模块列表菜单在现有数据库中进行更新。
完成插件模块的声明
声明是Odoo模块的重要部分。
准备工作
我们应该有了一个包含__manifest__.py
声明文件的模块。可以参考前面小节来实现这样的模块。
操作步骤
我们为插件模块添加一个声明文件和图标:
- 编辑模块的
__manifest__.py
文件,使其看起来像这样:
1234567891011121314151617{'name': "Hostel Management",'summary': "Manage Hostel easily",'description': "Efficiently manage the entire residential facility in the school.", # Supports reStructuredText(RST) format (description is Deprecated),'author': "Your name",'website': "http://www.example.com",'category': 'Uncategorized','version': '17.0.1.0.0','depends': ['base'],'data': ['views/hostel.xml'],'assets': {'web.assets_backend': ['web/static/src/xml/**/*',],},'demo': ['demo.xml'],} - 要对模块添加图标,请选择一个PNG图像并将其复制到
static/description/icon.png
。
工作原理
清单文件中的内容是一个普通的Python字典,包含键和值。我们使用的示例声明文件包含相关性最高的键:
- name:这是模块的标题。
- summary:这是单行描述副标题。
- description:这是用纯文本或ReStructuredText(RST)格式编写的长描述。通常用三引号包围,在Python中用于界定多行文本。有关RST的快速入门参考,请访问:http://docutils.sourceforge.net/docs/user/rst/quickstart.html。
- author:这是作者姓名符串。如果有多个作者,通常用逗号分隔,但注意它仍然是一个字符串,而不是Python列表。
- website:这是供人们访问以了解更多关于模块或作者的信息的URL。
- category:用于按兴趣领域组织模块。可用的标准类别名称列表请见https://github.com/odoo/odoo/blob/17.0/odoo/addons/base/data/ir_module_category_data.xml。但也可以在此处定义其他新类别名称。
- version:这是模块的版本号。Odoo应用商店可以通过它来检测安装模块的较新版本。如果版本号不是以Odoo目标版本(例如17.0)开头,将会自动添加。不过,如果明确说明Odoo目标版本会更具信息量,例如使用17.0.1.0.0或17.0.1.0,而不是1.0.0或1.0。
- depends:这是一个包含其直接依赖模块技术名称的列表。如果你的模块不依赖于任何其他插件模块,那么至少应该添加一个base模块。不要忘记包含由此模块引用并定义了XML ID、视图或模型的各模块。这将确保它们按正确的顺序加载,避免出现难以调试的错误。
- data:这是一个相对路径列表,指向在模块安装或升级期间加载的数据文件。路径相对于模块根目录。通常,这些是XML和CSV文件,但也可能有YAML数据文件。这些将在第六章 管理模块数据中深入讨论。
- demo:这是一个相对路径列表,指向要加载的演示数据文件。只有在创建数据库时启用了演示数据标记,才会加载这些文件。
用于模块图标的图像为PNG文件static/description/icon.png
。
Odoo在主版本之间预计会有显著变化,因此如不进行转换和迁移工作,为一个主要版本构建的模块不太可能与下一个版本可能不太兼容。因此,确定模块的Odoo目标版本非常重要。
为了确保兼容性,我们需要遵循这些步骤:
- 首先检查安装是否成功。如果成功,则继续检查模块功能是否正常工作。
- 如果安装不成功,则需要根据收到的错误调整代码和功能逻辑。
更多内容
除了在模块声明中的长描述,还可以有一个单独的描述文件。从8.0版开始,可以用README文件(带.txt、.rst或.md扩展名)替代。否则,包含模块的description/index.html文件。
这个HTML描述将覆盖声明文件中定义的描述。
还有一些常用的键:
- license:默认值是LGPL-3。这个标识符用于模块的许可。其他许可选项有AGPL-3、Odoo Proprietary License v1.0(主要用于付费应用)和其他OSI批准的许可。
- application:如果为True,模块会被列为应用程序。通常用于功能区的中央模块。
- auto_install:如果为True,表示这是一个胶水模块,当所有依赖项都安装时会自动安装。
- installable:如果为True(默认值),表示模块可安装。
- external_dependencies:某些Odoo模块内部使用Python/bin库。如果你的模块使用这些库,需要在此处列出。这将阻止用户在主机上未安装列出的库时安装模块。
- {pre_init, post_init, uninstall}_hook:这是一个在安装/卸载期间调用的Python函数钩子。详细示例请参见第八章 高级服务器端开发技术。
- assets:定义所有静态文件如何在各种资源包中加载。Odoo资源按包分组。每个包(一个特定类型的文件路径列表 – xml、js、css或scss)在模块声明中列出。
还有一些特殊键用于应用商店列表:
- price:此键用于设置插件模块的价格。此键的值应为整数。如果未设置价格,表示你的应用程序是免费的。
- currency:这是价格的货币。可能为USD或EUR。此键的默认值是EUR。
- live_test_url:如果想为你的应用提供实时测试URL,可以使用此键在应用商店中显示实时预览按钮。
- iap:如果模块用于提供IAP服务,请设置你的IAP开发者密钥。
- images:给出图像的路径。此图像将在Odoo应用商店中用作封面图像。
组织插件模块的文件结构
插件模块包含代码文件和其他资源,如XML文件和图片。对于大多数这些文件,我们可以自由选择将它们放置在模块目录的何处。
然而,Odoo对模块结构有一些约定,所以建议遵循这些约定。良好的代码可以提高可读性,简化维护,帮助调试,降低复杂性,并提升可靠性。这些适用于每一个新模块和所有新的开发项目。
准备工作
我们需要有一个仅包含__init__.py
和__manifest__.py
文件的插件模块目录。本节中,假定这个目录是local-addons/my_hostel。
如何操作…
按以下步骤为插件模块创建一个基本框架:
- 为代码文件创建目录:
1234567891011121314$ cd local-addons/my_hostel$ mkdir models$ touch models/__init__.py$ mkdir controllers$ touch controllers/__init__.py$ mkdir views$ touch views/views.xml$ mkdir security$ mkdir wizards$ touch wizards/__init__.py$ mkdir reports$ mkdir data$ mkdir demo$ mkdir i18n - 编辑模块的顶层
__init__.py
文件,加载子目录中的代码:
123from . import modelsfrom . import controllersfrom . import wizards
这样我们会有一个包含最常用目录的结构,类似这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
my_hostel ├── __init__.py ├── __manifest__.py ├── controllers │ └── __init__.py ├── data ├── demo ├── i18n ├── models │ └── __init__.py ├── security ├── static │ ├── description │ └── src │ ├─ js │ ├─ scss │ ├─ css │ └ xml ├── reports ├── wizards │ └── __init__.py └──views └── __init__.py |
工作原理
Odoo插件模块可以有三种类型的文件:
- Python代码:通过
__init__.py
文件加载,其中导入了 .py 文件和代码子目录。包含Python代码的子目录也需要自己的__init__.py
文件。 - 数据文件:需要在模块声明
__manifest__.py
的data和demo键中声明待加载的文件,通常是用于用户界面、测试夹具数据和演示数据的XML和CSV文件。也可以有YAML文件,包含在模块加载时运行的一些过程指令,例如以编程方式生成或更新记录,而不是静态地在XML文件中。 - Web资产:如JavaScript代码和库、CSS、SASS和QWeb/HTML模板,这些文件用于构建UI部分并管理这些UI元素中的用户操作。它们通过声明文件的资产清单键声明,包含新文件和现有文件,将这些资产添加到Web客户端、小部件或网页。
插件文件在以下目录中进行组织:
- models/:包含后端代码文件,从而创建模型及其业务逻辑。每个模型一个文件,建议与模型同名,例如,hostel.py对应hostel.hostel模型。在第四章 应用模型中将详细讨论。
- views/:包含用于用户界面的XML文件,有动作、表单、列表等。像模型一样,建议每个模型一个文件。网站模板的文件名应以_template为后缀。后端视图在第九章 后端视图中讲解,网站视图在第十四章 CMS网站开发中讨论。
- data/:包含模块初始数据的其他数据文件。数据文件在第六章 管理模块数据中讲解。
- demo/:包含演示数据文件,用于测试、训练或模块评估。
- i18n/:Odoo查找翻译文件.pot和.po的地方。详情请参阅第十一章 国际化。这些文件不需要在声明文件中提及。
- security/:包含定义访问控制列表的数据文件,通常是一个ir.model.access.csv文件,并且可能有一个XML文件,用于定义访问组和行级安全的记录规则。第十章 权限安全中详细介绍了这些内容。
- controllers/:包含网站控制器和提供此类功能的模块的代码文件。网络控制器在第十三章 Web服务器开发中介绍。
- static/:所有Web资产通常放置的地方。与其他目录不同,此目录名不仅仅是一个约定。此目录中的文件是公开的,无需用户登录即可访问。这个目录主要包含JavaScript、样式和图片等文件。它们不需要在模块声明中提及,但必须在Web模板中引用。在第十四章CMS网站开发中详细讨论。
- wizards/:包含与向导相关的所有文件。在Odoo中,向导用于保存中间数据。我们在第八章 高级服务器端开发技术中学习更多关于向导的内容。
- reports/:Odoo提供生成PDF文档(如销售订单和发票)的功能。此目录包含与PDF报表相关的所有文件。我们将在第十二章 自动化、工作流、电子邮件和打印中学习更多关于PDF报表的内容。
添加新文件到模块时,记得在__manifest__.py
文件(对于数据文件)或__init__.py
文件(对于代码文件)中声明它们,否则这些文件将被忽略且不会加载。
添加模型
模型定义将由我们的业务应用程序使用的数据结构。本节展示如何向模块添加基本模型。模型确定数据库的逻辑结构以及数据如何存储、组织和操作。换句话说,模型是可以与其他表链接的信息表。模型通常表示业务概念,如销售订单、联系人或产品。
模块包含各种元素,如模型、视图、数据文件、网页控制器和静态web数据。
要创建一个公寓模块,我们需要开发表示公寓的模型。
准备工作
我们应有一个可用的模块。如果你按照本章中的第一个小节创建和安装一个新插件模块进行操作,就会有一个名为my_hostel的空模块。我们将使用它进行说明。
如何操作…
要添加一个新模型,我们需要添加一个描述它的Python文件,然后升级插件模块(如尚未安装)。使用的路径是相对于我们的插件模块位置(例如, ~/odoo-dev/local-addons/my_hostel/):
- 添加一个Python文件到models/hostel.py模块,代码如下:
123456789from odoo import fields, modelsclass Hostel(models.Model):_name = 'hostel.hostel'_description = "Information about hostel"name = fields.Char(string="Hostel Name", required=True)hostel_code = fields.Char(string="Code", required=True)street = fields.Char('Street')street2 = fields.Char('Street2')state_id = fields.Many2one("res.country.state", string="State") - 在models/__init__.py模块中添加一个Python初始化文件,加载代码文件:
1from . import hostel - 编辑模块的Python初始化文件加载models/目录:
1from . import models - 通过命令行或用户界面的Apps菜单升级Odoo模块。如果在升级模块时仔细查看服务器日志,应该会看到以下行:
1odoo.modules.registry: module my_hostel: creating or updating database table
之后,应该在我们的Odoo实例中可以使用新的hostel.hostel模型。有两种方法可以检查模型是否已添加到数据库中。
首先,可以在Odoo用户界面中检查。启用开发者工具并打开菜单Settings | Technical | Database Structure | Models。在这里搜索hostel.hostel模型。
第二种方法是检查PostgreSQL数据库中的数据表。可以在数据库中搜索hostel_hostel表。在以下代码示例中,我们使用test-17.0作为数据库名称。但你可以在以下命令替换你的数据库名称:
1 2 |
$ psql test-17.0 test-17.0# \d hostel_hostel; |
工作原理
第一步是创建一个Python文件,在其中创建我们的新模块。
Odoo框架有自己的对象关系映射(ORM)框架。这个ORM框架在PostgreSQL数据库之上提供了一个抽象层。通过继承Odoo的Model类,我们可以创建自己的模型(表)。定义新模型时,它也会被添加到中央模型注册表中。这样其他模块可以更容易地修改它。
模型有一些前缀为下划线的通用属性。最重要的是_name,它提供了一个唯一的内部标识符,将在整个Odoo实例中使用。ORM框架将基于这个属性生成数据库表。在我们的示例中,我们使用了_name = ‘hostel.hostel’。基于这个属性,ORM将生成一个名为hostel_hostel的表。可以看到ORM框架会通过将_name属性中的.替换为_来创建表名。_description提供了模型的非正式名称,我们使用_name = ‘hostel.hostel’和_description=’Information about hostel’,_description=’Information about hostel’仅能以字母开头,不能用数字或特殊字符开头。
模型字段被定义为类属性。我们首先定义了一个Char类型的name字段。这个字段对于模型是很方便的,因为默认情况下,当其他模型引用时,它会用作记录描述。
我们还使用了一个关系字段示例——state_id。它定义了Hostel和State之间的一对多关系。
关于模型,还有很多内容,我们将在第四章 应用模型中深入讨论。
接下来,必须让我们的模块知道这个新的Python文件。这是通过__init__.py
文件实现的。由于我们将代码放在models/子目录中,我们需要在之前的__init__.py
文件中导入该目录,进而包含另一个__init__.py
文件,导入其中的每个代码文件(本例中只有一个)。
通过升级模块来启用对Odoo模型的更改。Odoo服务器将处理模型类到数据库结构更改的翻译。
虽然这里没有提供示例,但业务逻辑也可以添加到这些Python文件中,方法是向模型类添加新方法或扩展现有方法,如create()或write()。这将在第五章 基础服务端开发中介绍。
添加访问安全
添加新数据模型时,需要定义谁可以创建、读取、更新和删除记录。在创建全新应用程序时,这可能涉及定义新的用户组。因此,如果用户没有这些访问权限,Odoo将不会显示您的菜单和视图。在前面的小节中,我们通过将admin用户转换为超级用户来访问我们的菜单。完成本节后,读者将能够直接以admin用户身份访问Hostel模块的菜单和视图。
本节基于之前的Hostel模型,并定义了一个新的用户安全组,控制谁可以访问或修改Hostel记录。
准备工作
需要在前面小节中提供的实现hostel.hostel模型的插件模块,因为在本节中,我们将为其添加安全规则。使用我们插件模块位置的相对路径(例如,~/odoo-dev/local-addons/my_hostel/)。
如何操作…
本节中添加的安全规则如下:
- 所有人都可以读取公寓记录。
- 一个名为Hostel Manager的新用户组将有权创建、读取、更新和删除公寓记录。
需要执行以下步骤进行实现:
- 创建一个名为security/hostel_security.xml的文件,内容如下:
12345678910111213141516<?xml version="1.0" encoding="utf-8"?><odoo><record id="module_category_hostel" model="ir.module.category"><field name="name">Hostel Management</field><field name="sequence">31</field></record><record id="group_hostel_manager" model="res.groups"><field name="name">Hostel Manager</field><field name="category_id" ref="module_category_hostel"/><field name="users" eval="[(4, ref('base.user_root')),(4, ref('base.user_admin'))]"/></record><record id="group_hostel_user" model="res.groups"><field name="name">Hostel User</field><field name="category_id" ref="module_category_hostel"/></record></odoo> - 添加一个名为security/ir.model.access.csv的文件,内容如下:
123id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlinkaccess_hostel_manager_id,access.hostel.manager,my_hostel.model_hostel_hostel,my_hostel.group_hostel_manager,1,1,1,1access_hostel_user_id,access.hostel.user,my_hostel.model_hostel_hostel,my_hostel.group_hostel_user,1,0,0,0 - 将这两个文件添加到
__manifest__.py
中:
1234567# ..."data": ["security/hostel_security.xml","security/ir.model.access.csv","views/hostel.xml",],# ...
更新实例中的插件模块后,新定义的安全规则将生效。
工作原理…
我们提供了两个新的数据文件,并将它们添加到插件模块的声明中,以便在安装或更新模块时将它们加载到数据库中:
- security/hostel_security.xml文件通过创建res.groups记录定义了一个新的安全组。我们还通过使用其引用ID,base.user_admin,赋予admin用户公寓管理权限,以使用管理员用户具有对hostel.hostel模型的权限。
- ir.model.access.csv文件将模型上的权限与组关联起来。第一行的group_id:id列为空,意味着该规则适用于所有人。最后一行赋予我们刚刚创建的组的成员所有权限。
声明文件数据部分的文件顺序很重要。创建安全组的文件必须在列出访问权限的文件之前加载,因为访问权限定义依赖于组的存在。由于视图可能特定于某个安全组,我们建议将组的定义文件放在列表中以确保安全。
参见
本书有一章专门介绍安全。有关安全的更多信息,请参见第十章 安全访问。
添加菜单项和视图
有了数据结构所需的模型,我们就需要一个用户界面,以便用户与之交互。菜单和视图在构建和提升用户体验方面起着至关重要的作用。从技术角度来看,菜单是动态用户界面组件,呈现一组结构化的选项或链接,通常允许用户访问应用程序中的各种功能、函数或内容区域。本节基于之前的Hostel模型,添加了一个菜单项,以显示带有列表和表单视图的用户界面。
准备工作
需要在前面小节中提供的实现hostel.hostel模型的插件模块。使用我们插件模块位置的相对路径(例如,~/odoo-dev/local-addons/my_hostel/)。
如何操作…
要添加视图,我们将向模块添加一个定义视图的XML文件。由于这是一个新模型,我们还必须为用户添加一个菜单选项,以便能够访问它。
对于模型,XML文件添加视图文件夹来创建视图、动作和菜单项。
请注意,以下步骤的顺序很重要,因为其中一些使用了在前面的步骤中定义的ID引用:
- 创建XML文件添加描述用户界面的数据记录,views/hostel.xml:
1234<?xml version="1.0" encoding="utf-8"?><odoo><!-- Data records go here --></odoo> - 将新的数据文件添加到插件模块声明文件
__manifest__.py
,在views/hostel.xml中添加以下内容:
123456{"name": "Hostel Management","summary": "Manage Hostel easily","depends": ["base"],"data": ["views/hostel.xml"],} - 在hostel.xml文件中添加打开视图的动作:
1234567891011<record id="action_hostel" model="ir.actions.act_window"><field name="name">Hostel</field><field name="type">ir.actions.act_window</field><field name="res_model">hostel.hostel</field><field name="view_mode">tree,form</field><field name="help" type="html"><p class="oe_view_nocontent_create">Create Hostel.</p></field></record> - 将菜单项添加到hostel.xml文件,使其对用户可见:
12<menuitem id="hostel_main_menu" name="Hostel" sequence="1"/><menuitem id="hostel_type_menu" name="Hostel" parent="hostel_main_menu" action="my_hostel.action_hostel" groups="my_hostel.group_hostel_manager" sequence="1"/> - 在hostel.xml文件中添加自定义表单视图:
12345678910111213141516171819202122232425262728293031323334353637383940414243<record id="view_hostel_form_view" model="ir.ui.view"><field name="name">hostel.hostel.form.view</field><field name="model">hostel.hostel</field><field name="arch" type="xml"><form string="Hostel"><sheet><div class="oe_title"><h3><table><tr><td style="padding-right:10px;"><field name="name"required="1"placeholder="Name" /></td><td style="padding-right:10px;"><field name="hostel_code"placeholder="Code" /></td></tr></table></h3></div><group><group><label for="street"string="Address"/><div class="o_address_format"><field name="street"placeholder="Street..."class="o_address_street"/><field name="street2"placeholder="Street 2..."class="o_address_street"/></div></group></group></sheet></form></field></record> - 在hostel.xml文件中添加自定义树状(列表)视图:
12345678910<record id="view_hostel_tree_view" model="ir.ui.view"><field name="name">hostel.hostel.tree.view</field><field name="model">hostel.hostel</field><field name="arch" type="xml"><tree><field name="name"/><field name="hostel_code"/></tree></field></record> - 将自定义添加搜索选项到hostel.xml文件:
12345678910<record id="view_hostel_search_view" model="ir.ui.view"><field name="name">Hostel Search</field><field name="model">hostel.hostel</field><field name="arch" type="xml"><search><field name="name"/><field name="hostel_code"/></search></field></record>
在Odoo中添加新模型时,用户默认没有任何访问权限。我们必须为新模型定义访问权限才能访问。本例中,我们尚未定义任何访问权限,因此用户无法访问我们的新模型。在没有访问权限的情况下,菜单和视图也不可见。所幸有一个快捷方式!通过切换到超级用户模式,可以在没有访问权限时看到我们应用的菜单。
以超级用户访问Odoo
通过将admin用户转换为superuser类型,可以绕过访问权限,无需授予默认访问权限即可访问菜单和视图。要将admin用户转换为超级用户,请启用开发者模式。完成此操作后,从开发者工具选项中单击成为超级用户选项。
开发者尽量在不成为超级用户的情况下进行所有操作;这将非常有助于深入学习Odoo。成为超级用户后,所有安全访问和记录规则检查将被绕过。
The following screenshot has been provided as a reference:
以下截图可供参考:
图3.3 – 启用超级用户模式的选项
成为超级用户后,菜单将具有条纹背景,如下图所示:
图3.4 – 启用超级用户模式
此时如尝试升级模块,应该能够看到一个新的菜单选项(可能需要刷新浏览器)。单击Hostel菜单将打开公寓模型的列表视图,如下图所示:
图3.5 – 访问公寓菜单
工作原理…
在底层,用户界面由存储在特殊模型中的记录定义。前两步是创建一个空的XML文件来定义要加载的记录,然后将它们添加到模块的待安装数据文件列表中。
数据文件可以放置在模块目录的任何位置,但按照惯例,用户界面通常在views/子目录中定义。这些文件的名称通常基于模型的名称。本例中,我们为hostel.hostel模型创建了用户界面,所以创建了views/hostel.xml文件。
下一步是定义一个窗口动作,以在网页客户端的主要区域显示用户界面。这个动作由res_model定义目标模型,name属性用于在用户打开动作时显示标题。这只是基本属性。窗口动作支持额外的属性,给予对视图渲染更多的控制,例如显示哪些视图、对可用记录添加过滤器或设置默认值。这些将在第九章 后端视图中详细讨论。
一般来说,数据记录使用<record>
标签定义,我们在示例中为ir.actions.act_window模型创建了一个记录。这将创建窗口动作。
同样,菜单项存储在ir.ui.menu模型中,我们可以使用<record>
标签创建这些菜单项。但在Odoo中有一个叫做<menuitem>
的快捷标签,所以我们在示例中使用了这个标签。
以下是菜单项的主要属性:
- name:这是要显示的菜单项文本。
- action:这是要执行的动作标识符。我们使用上一步创建的窗口动作的ID。
- sequence:用于设置同一级别菜单项的显示顺序。
- parent:这是父菜单项的标识符。我们的示例菜单项没有父菜单项,表示它会显示在菜单的顶部。
- web_icon:此属性用于显示菜单的图标。该图标仅在Odoo企业版中显示。
此时,我们还没有在模块中定义任何视图。但是,如果在这个阶段升级模块,Odoo会自动动态创建这些视图。不过,我们肯定想控制视图的外观,因此在接下来的两步中,将创建一个表单视图和一个树状视图。
这两种视图都通过ir.ui.view模型上的记录定义。我们使用的属性如下:
- name:这是都没说啥视图的标题。在Odoo的源代码中,会发现与XML ID重复,但如果需要,可以添加一个更易读的标题作为名称。
- 如果省略name字段,Odoo将使用模型名称和视图类型生成一个名称。这对于新模型的标准视图非常合适。扩展视图时,建议使用更明确的名称,在查找特定视图时更加方便。
- model:这是目标模型的内部标识符,就像其_name属性的定义。
- arch:这是视图的架构,实际上定义了其结构。不同类型的视图在这里有所不同。
表单视图用顶层<form>
元素定义,其画布为两列网格。在表单中,<group>
元素用于垂直排列字段。两个组元素产生两列中排列字段,这些字段使用<field>
元素添加。字段根据其数据类型使用默认小部件,但可以使用widget属性来指定小部件。
树状视图更简单;它们用顶层<tree>
元素定义,其中包含显示字段的<field>
元素。
最后,我们添加了一个搜索视图,扩展右上角的搜索选项。在顶层<tag>
中,我们可以有<field>
和<filter>
元素。Field元素是可以从搜索视图中输入内容进行搜索的附加字段。Filter元素是可以点击激活的预定义过滤条件。这些话题将在第九章 后端视图中详细讨论。
使用scaffold命令创建模块
在新建Odoo模块时,需要设置一些样板代码。为快速启动新模块,Odoo提供了scaffold命令。
本节展示如何使用scaffold命令新建模块,它为要使用的目录放置文件的骨架。
准备工作
我们将在自定义模块目录中创建新的插件模块,因此我们需要安装Odoo以及要有一个自定义模块目录。假定Odoo安装在~/odoo-dev/odoo,并且我们的自定义模块放在~/odoo-dev/local-addons目录中。
操作步骤
我们将使用scaffold命令创建样板代码。按以下步骤使用scaffold命令创建新模块:
- 将工作目录切换为我们希望模块所在的位置。可以是您选择的任何目录,但它需要在插件路径中才可用。按照我们在前一节中选择的目录,应如下所示:
1$ cd ~/odoo-dev/local-addons
- 为新模块选择一个技术名称,并使用scaffold命令创建它。本例我们将选择my_module:
1$ ~/odoo-dev/odoo/odoo-bin scaffold my_module - 编辑
__manifest__.py
默认模块声明并更改相就值。至少需要更改name键中的模块标题。
生成的插件模块应如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ tree my_module my_module/ ├── __init__.py ├── __manifest__.py ├── controllers │ ├── __init__.py │ └── controllers.py ├── demo │ └── demo.xml ├── models │ ├── __init__.py │ └── models.py ├── security │ └── ir.model.access.csv └── views ├── templates.xml └── views.xml 5 directories, 10 files |
现在应编辑生成的各个文件,并使它们适应新模块的用途。
工作原理…
scaffold命令根据模板创建新模块的骨架。
默认情况下,在当前工作目录中新建模块,但我们可以指定目录来创建模块,以额外参数传递。
考虑以下示例:
1 |
$ ~/odoo-dev/odoo/odoo-bin scaffold my_module ~/odoo-dev/local-addons |
使用的是默认模板,但也用theme模板创建网站主题。要指定模板,可以使用-t选项。我们也可以使用模板目录的路径。
这意味着我们可以将自己的模板与scaffold命令一起使用。内置模板位于Odoo子目录/odoo/cli/templates中。要使用我们自己的模板,可以用如下命令:
1 |
$ ~/odoo-dev/odoo/odoo-bin scaffold -t path/to/template my_module |
默认,Odoo在/odoo/cli/templates目录中有两个模板。一个是默认模板,另一个是主题模板。但可以自建模板或使用-t选项,如上例所示。