現在我們已經有了開發環境並了解了如何管理實例及數據庫,現在讓我們來學習下如何創建插件模塊。
本章內容如下:
- 創建和安裝模塊
- 完成manifest文件
- 組織模塊文件結構
- 添加模型
- 添加菜單及視圖
- 添加訪問控制
- 使用scaffold命令創建模型
在odoo中什么是模塊(add-on module)?
除了框架代碼,其他的代碼都是以模塊的形式組織起來的。這些模塊可以隨時安裝和卸載。由於odoo用於各種規模的公司,每一個公司都有自己的業務流程。為了解決這一個問題,應用將應用拆分到不同的模塊當中。這些模塊在需要的時候才會被載入。我們可以隨時啟停這些功能。同一個應用也可以適配不同的需求。如下截圖當中是以不同的應用分組,每一組第一個應用是主模塊,其余的是屬於其輔助模塊。
在創建應用時應該創建各個功能的邊界。這將非常有助於將應用程序划分為不同的附加模塊。下面讓我們開始構建自己的附加模塊了。
創建和安裝新應用
准備
在用的odoo實例
步驟
作為例子,我們這一章將創建一個管理圖書的模塊。
- 進入項目工程,創建本地目錄。
$ cd ~/odoo-dev
$ mkdir local-addons
- 創建項目目錄
$ mkdir local-addons/my_library
- 創建__init__.py文件
$ touch local-addons/my_library/__init__.py
- 創建__manifest__.py文件,並寫入
{'name': 'My Library'}
- 將本地目錄配置到odoo路徑中。
$ odoo/odoo-bin --addons-path=odoo/addon/,local-addons/
如果我們在命令行中使用--save,那么相應的配置會存儲的配置文件下次使用的時候就會更方便了。
6. 通過在APP頁面刷新本地目錄按鈕,可以在列表當中查看到我們新建的項目。
- 安裝
原理
odoo模塊是包含着源代碼及其他文件的目錄。該文件夾名稱通常是模塊的技術名稱。
manifest.py是Python的字典包含着模塊兒的相關信息。
模塊必須是可導入的,也就是說它必須具備__init__.py文件,即使這個文件時空的。
完成模塊的__manifest__.py文件
准備
上一節內容
步驟
- 編輯__manifest__.py文件
'name': "My library",
'summary': "Manage books easily",
'description': """
Manage Library
==============
Description related to library.
""",
'author': "Your name",
'website': "http://www.example.com",
'category': 'Uncategorized',
'version': '13.0.1',
'depends': ['base'],
'data': ['views/views.xml'],
'demo': ['demo.xml'],
}
- 為模塊選擇一個icon圖標,放置在static/description/icon.png中。
原理
- name: 模塊的名稱。
- summary: 模塊的簡單介紹。
- description: 模塊的長介紹。通常是純文本或者ReStructuredText (RST) 格式。
- author: 模塊作者。
- website: 模塊開發者的網站。
- category: 模塊的分類。關於模塊分類有一個標准的列表可供選擇( https://github.com/odoo/ odoo/blob/13.0/odoo/addons/base/data/ir_module_category_ data.xml. )。當然你也可以定義自己的名稱。
- version: 模塊的版本。這通常用於odoo檢測是否有新的版本需要升級。如果所輸入的版本當中並不包含包含odoo的主版本(12.0,13.0,14.0),odoo將自動添加。
- depends: 這是當前模塊所依賴的其他模塊。即便模塊不依賴於其他的模塊兒的話,要么也應該輸入base模塊。在填寫依賴的時候應注意依賴的順序。
- data: 這是數據文件的列表。數據文件的路徑是相對於模塊的根路徑的通常是xml及csv文件。也可以是yaml文件,這在第六章進行介紹。
- demo: 這關聯模塊兒的演示數據。
由於odoo主版本之間存在蠻多的不同一個模塊兒,可能並不是用於其他的版本。
更多
在__manifest__.py的description中,也可以是單獨的描述性文件。自odoo8之后,支持README文件或者其他的txt、rst、md擴展名的文件。或者直接展示在description/index.html的內容。
html文件將直接復寫描述中的內容。
還有幾個關鍵的key
- licence: 默認是LGPL-3協議。
- application: True/False,當前模塊是否是核心模塊。
- auto_install: True/False,代表是否在其所依賴的模塊完成安裝后自動安裝。
- installable: True/False,代表當前模塊是否可安裝。
- external_dependencies: 一些模塊可能依賴於Python或bin包。如果當前環境不具備,這些內容那么安裝將停止。
- {pre_init, post_init, uninstall}_hook: 這里代表python的函數,分別是安裝前,安裝后,卸載時運行(詳細將在第八章介紹)
還有幾個特殊的key - price: 代表當前模塊兒的售價,如果沒有設置的話,那么代表免費。
- currency: 代表當前模塊兒售價的單位。默認是EUR。
- live_test_url: 表示在線試用的鏈接。
- iap: 如果模塊提供IAP服務,請填寫IAP的key。
- images: images的路徑,這些圖片用於在odoo的app商城上展示。
組織模塊文件結構
模塊當中包含源代碼及其他各種各樣的文件,雖然我們可以隨便放置,但是建議還是按照模塊的結構進行規范化。
准備
假定我們的模塊位於local-addons/my_ library,並包含了__manifest__.py,__init__.py文件。
- 創建目錄及文件
$ cd local-addons/my_library
$ mkdir models
$ touch models/__init__.py
$ mkdir controllers
$ touch controllers/__init__.py
$ mkdir views
$ touch views/views.xml
$ mkdir security
$ mkdir wizard
$ touch wizard/__init__.py
$ mkdir report
$ mkdir data
$ mkdir demo
$ mkdir i18n
- 編輯__init__.py文件
from . import models
from . import controllers
from . import wizard
大部分目錄結構式如下
my_library
├── __init__.py
├── __manifest__.py
├── controllers
│ └── __init__.py
├── data
├── demo
├── i18n
├── models
│ └── __init__.py
├── security
├── static
│ ├── description
│ └── src
│ ├─ js
│ ├─ scss
│ ├─ css
│ └ xml
├── report
├── wizard
│ └── __init__.py
└──views
└── __init__.py
原理
odoo中主要有三種類型的文件
- Python: .py文件,包含模型對象、業務邏輯
- Data文件: 定義在data及demo的key中。通常是XML及CSV文件。YAML文件也可以,他可以在模塊加載的時候執行一些指令。對於實例而言,相較於xml的靜態更新,yaml可以實現動態生成和更新記錄。
- Web assets是JavaScript、CSS、SCSS及QWeb/HTML模板的集合。這些文件通常用於構建友愛頁面以及管理用戶的點擊行為。還有一些被定義為XML的文件,去擴成主模板的功能。
模塊文件通過如下方式進行組織:
- models/: 包含模塊的模型對象定義及其業務邏輯。詳見第四章應用模型
- views/: 包含定義用戶交互的xml文件。包括動作、form視圖、list視圖等。建議每一個模型都有單獨的xml文件。網站模板的文件名建議以_template后綴。后端視圖將在第九章后端視圖介紹,網站視圖將在第十四章CMS開發介紹。
- data/: 包含模型的初始化數據。將在第六章管理模塊數據介紹。
- demo/: 包含演示數據,用於測試。
- il8n/: 用於存放翻譯文件。以.pot及.po文件為主。將在第十一章,國際化中進行介紹。
- security/: 包含權限控制的相關文件。包括ir.model.access.csv,xml文件(定義權限組及記錄規則信息)。詳見第十章權限控制。
- controllers/: 包含web網站的訪問定義等業務邏輯。詳見第十三章,web服務開發。
- static/: 網站相關的定義文件。這里的文件是允許非登錄用戶訪問的。主要包括JavaScript、樣式文件及images。這並不需要在manifest中引用,但需要在web模板中引用。詳見第十四章,CMS開發。
- wizard/: 包含向導相關的文件。在odoo中,wizard用於保存中間數據。詳見第八章,服務端開發-進階。
- report/: odoo提供了生成pdf文件的特性。這里將用於生成的pdf報告的相關文件。詳見第十二章,自動化、流程、郵件及打印。
當我們添加了新的文件后,不要忘記在__manifest__.py及__init__.py中進行引用。
添加模型
模型定了我們業務邏輯中的數據結構。
在這一章節當中,我們將添加圖書模型。
准備
步驟
- 添加模型文件models/library_book.py
from odoo import models, fields
class LibraryBook(models.Model):
_name = 'library.book'
name = fields.Char('Title', required=True)
date_release = fields.Date('Release Date')
author_ids = fields.Many2many(
'res.partner',
string='Authors'
)
- 將新增文件添加到models/init.py
from . import library_book
- 編輯模塊的初始化文件__init__.py
from . import models
- 通過頁面UI或者命令行更新模塊
現在模型已添加到數據庫中了。可通過兩種方式查看: - 通過odoo的頁面,在菜單 Settings|Technical|Database Structure|models下查找目標模型。
- 進入數據庫查看
$ psql test-13.0
test-13.0# \d library_book;
原理
odoo中有自己的的Object Relations Mapping(ORM)框架。orm框架提供了對postgresql數據庫的抽象。通過繼承odoo的python類model,我們能夠創建自己的模型。
模型有幾個通用的以_為前綴的屬性。最重要的是_name,它是模型的唯一標識。ORM框架生成數據庫表也是基於這個屬性。數據庫表明是將name中的”.“替換為”_“。
我們新增了模型文件后,需要將其添加到同目錄的__init__.py文件中。
添加菜單及視圖
這節我們將實現頁面菜單及視圖的展示。
准備
步驟
菜單和視圖都是以xml文件的形式存在。
- 創建xml文件以添加數據記錄,views/library_book.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Data records go here -->
</odoo>
- 將新增的xml文件添加到__manifest__.py文件中
{
'name': "My Library",
'summary': "Manage books easily",
'depends': ['base'],
'data': ['views/library_book.xml'],
}
- 在library_book.xml中添加動作action(用於打開視圖)
<record id='library_book_action' model='ir.actions.act_ window'>
<field name="name">Library Books</field>
<field name="res_model">library.book</field>
<field name="view_mode">tree,form</field>
</record>
- 添加菜單,並將action關聯到菜單上
<menuitem name="My Library" id="library_base_menu" />
<menuitem name="Books" id="library_book_menu" parent="library_base_menu" action="library_book_action"/>
- 在library_book.xml中添加form視圖
<record id="library_book_view_form" model="ir.ui.view">
<field name="name">Library Book Form</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="name"/>
<field name="author_ids" widget="many2many_tags"/>
</group>
<group>
<field name="date_release"/>
</group>
</group>
</form>
</field>
</record>
- 添加tree(list)列表視圖
<record id="library_book_view_tree" model="ir.ui.view">
<field name="name">Library Book List</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="date_release"/>
</tree>
</field>
</record>
- 添加搜索視圖
<record id="library_book_view_search" model="ir.ui.view">
<field name="name">Library Book Search</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<field name="author_ids"/>
<filter string="No Authors"
name="without_author"
domain="[('author_ids','=',False)]"/>
</search>
</field>
</record>
- 當一個新的模型添加到odoo中后,默認是沒有訪問權限的,這樣菜單及視圖也是看不到的。我們可以通過進入超級管理員模式去查看相關內容。
進入超級管理員模式
進入管理員模式后,右上角視圖將變成
原理
數據文件可以放在模塊目錄中的任何位置,但約定是在視圖/子目錄中定義用戶界面。通常,這些文件的名稱基於模型的名稱。在本例中,我們正在為圖書館.book模型,所以我們創建了 views/library_book.xml文件。
下一步是定義一個窗口操作。動作操作的目標模型定義在res_model中,name屬性用於在用戶打開動作時向用戶顯示標題。這些只是基本屬性。窗口操作支持附加屬性,從而可以更有效地控制視圖的呈現方式,例如顯示哪些視圖、在可用記錄上添加過濾器或設置默認值。在第9章后端視圖中詳細討論了這些問題。
通常,數據記錄是使用
相似,菜單是添加到ir.ui.menu模型中。我們也可以使用
- name: 菜單展示的內容
- action: 點擊菜單后出發的動作
- sequence: 菜單的展示順序
- parent: 代表當前菜單所屬的父級菜單
- web_icon: 標識顯示在菜單上的icon圖標。這個只在企業版生效。
截止目前,我們還沒有添加視圖。但是如果我們更新模塊,那么odoo將自動創建默認的視圖。
所有的視圖都是定義在ir.ui.view模型中的。主要屬性如下: - name: 視圖的標題。如果沒寫,odoo將視同模型的名稱及視圖的類型自動生成一個。
- model: 這是視圖所屬的模型。
- arch: 這是視圖的架構。
Form視圖是定義在
添加訪問控制
在我們的前面提到的model、view、menu都涉及到權限控制。
在odoo中,權限是以組的形式展開的。用戶屬於某些權限組,通過對權限組進行授權實現對model、view、menu的控制。
准備
步驟
- 權限組,security/groups.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="group_librarian" model="res.groups">
<field name="name">Librarians</field>
<field name="users" eval="[(4, ref('base.user_ admin'))]"/>
</record>
</odoo>
- 通過security/ir.model.access.csv進行模型權限的配置
id,name,model_id:id,group_id:id,perm_read,perm_ write,perm_create,perm_unlink
acl_book,library.book default,model_library_book,,1,0,0,0
acl_book_librarian,library.book_librarian,model_library_ book,group_librarian,1,1,1,1
- 將以上文件添加到__manifest__.py中
# ...
'data': [
'security/groups.xml',
'security/ir.model.access.csv',
'views/library_book.xml'
],
# ...
原理
以上我們涉及了權限組的創建及對權限組進行模型授權
- security/groups.xml,定義了權限組,id為權限組的唯一標識,name是權限組的名稱,users是權限組初始化時包含的用戶。其實groups也是將權限組的記錄寫入res.groups模型中。
- ir.model.access.csv文件,定義了權限組對於模型的訪問權限。其實就是將csv中的信息寫入ir.model.access模型中。
使用scaffold命令創建模型
之前我們自己構建了模塊的結構,但是其實odoo提供了簡單構建模塊的命令: scaffold。
准備
步驟
- 進入本地模塊所在目錄,如下:
$ cd ~/odoo-dev/local-addons
- 通過命令創建模塊, scaffold 模塊的技術名稱
$ ~/odoo-dev/odoo/odoo-bin scaffold my_module
- 如下是命令自動創建的模塊架構
$ 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是基於模板創建新模塊的。
默認是創建在當前目錄下,也可指定存儲的目錄。
$ ~/odoo-dev/odoo/odoo-bin scaffold my_module ~/odoo-dev/local- addons
odoo中是有兩個模板的,處於/odoo/cli/templates目錄中。一個是默認的模板,另一個主要用於網站主題。當然我們也可以使用我們自己的模板。通過-t指定模板存儲的路徑。
$ ~/odoo-dev/odoo/odoo-bin scaffold -t path/to/template my_ module