全書(shū)完整目錄請(qǐng)見(jiàn):Odoo 12開(kāi)發(fā)者指南(Cookbook)第三版
本章中,我們將講解如下內(nèi)容:
- 創(chuàng)建和安裝一個(gè)新的插件模塊
- 完成插件模塊的聲明
- 組織插件模塊文件結(jié)構(gòu)
- 添加模型
- 添加菜單項(xiàng)和視圖
- 添加訪問(wèn)權(quán)限
- 使用腳手架命令來(lái)創(chuàng)建模塊
技術(shù)準(zhǔn)備
本章中,我們將預(yù)設(shè)你已安裝了Odoo并且按照第一章 安裝Odoo開(kāi)發(fā)環(huán)境進(jìn)行的操作。你還應(yīng)熟悉第二章 管理Odoo服務(wù)器實(shí)例中所描述的查找和安裝附加的插件模塊。本章中所使用的代碼可以從如下GitHub倉(cāng)庫(kù)中進(jìn)行下載:https://github.com/alanhou/odoo12-cookbook/tree/master/Chapter04/my_library。
代碼實(shí)時(shí)操作的視頻請(qǐng)見(jiàn):http://t.cn/E9PzDbm
引言
現(xiàn)在我們已經(jīng)有了開(kāi)發(fā)環(huán)境并且知道如何管理Odoo實(shí)例和數(shù)據(jù)庫(kù),可以學(xué)習(xí)如何創(chuàng)建Odoo插件模塊了。
這里我們的主要目標(biāo)是理解一個(gè)插件模塊的結(jié)構(gòu)是什么樣的以及對(duì)其進(jìn)行補(bǔ)充的典型增量工作流。本章中各節(jié)所討論的各種組件會(huì)在后續(xù)章節(jié)中進(jìn)行擴(kuò)充講解。
Odoo的插件模塊是什么?
除框架代碼以外,Odoo的所有基礎(chǔ)代碼都以模塊的形式組合在一起。這些模塊可以隨時(shí)從數(shù)據(jù)庫(kù)中安裝或卸載。這些模塊有兩大目的。要么你可以添加新應(yīng)用/業(yè)務(wù)邏輯,要么你可以修改已有應(yīng)用。簡(jiǎn)言之,Odoo中的一切都始于模塊也終于模塊。
Odoo由不同規(guī)模的公司所使用,每個(gè)公司都有不同的業(yè)務(wù)流和要求。處理這一問(wèn)題,Odoo將應(yīng)用的功能拆分到了不同的模塊中。這些模塊可按需在數(shù)據(jù)庫(kù)中進(jìn)行加載。基本上,用戶可以在任何時(shí)間點(diǎn)啟用/禁用這些功能。因此,相同的軟件可以按不同的要求進(jìn)行調(diào)整。查看下面Odoo模塊的截屏;該列中第一個(gè)模塊是主應(yīng)用,其它的模塊為該應(yīng)用添加功能而設(shè)計(jì)。讓模塊列表按應(yīng)用分類(lèi)進(jìn)行分組,進(jìn)入Apps菜單并對(duì)Category應(yīng)用分組:

如果你計(jì)劃在Odoo中開(kāi)發(fā)新應(yīng)用,應(yīng)為不同功能設(shè)置邊界。這有助于將你的應(yīng)用切分為不同的插件模塊。既然你已經(jīng)知道了Odoo中插件模塊的用途,我們可以開(kāi)始構(gòu)建自己的插件模塊了。
創(chuàng)建和安裝一個(gè)新的插件模塊
這一節(jié)中,我們將新建一個(gè)模塊,讓其在我們的Odoo實(shí)例中可用并安裝它。
準(zhǔn)備工作
我們需要準(zhǔn)備好一個(gè)Odoo實(shí)例來(lái)開(kāi)始我們的開(kāi)發(fā)。
如果我按照第一章 安裝Odoo開(kāi)發(fā)環(huán)境的從源碼輕松安裝Odoo一節(jié)進(jìn)行操作的話,Odoo應(yīng)該在~/odoo-dev/odoo下。為方便講解,我們假定Odoo安裝在該路徑下,但是你可以使用其它你自己偏好的路徑。
我們還需要一個(gè)位置來(lái)安裝自己的Odoo模塊。就本節(jié)而言,我們將使用odoo的同級(jí)目錄:~/odoo-dev/local-addon。
如何操作...
本章的示例中,我們將創(chuàng)建一個(gè)小型的插件模塊來(lái)管理圖書(shū)館中的一系列圖書(shū)。
如下步驟將創(chuàng)建并安裝一個(gè)新的插件模塊:
- 進(jìn)入到工作目錄即你要操作并放置新建的自定義模塊的插件目錄中:
$ cd ~/odoo-dev
$ mkdir local-addons
- 為新模塊選擇一個(gè)技術(shù)名稱(chēng)并使用該名稱(chēng)作為模塊名創(chuàng)建目錄。本例中,我們將使用my_library:
$ mkdir local-addons/my_library
> ??模塊的技術(shù)名稱(chēng)必須是有效的Python標(biāo)識(shí)符,需以字母開(kāi)頭,僅包含字母、數(shù)字和下劃線。建議在模塊名稱(chēng)中只使用小寫(xiě)字母。
- 通過(guò)添加init.py文件來(lái)讓Python模塊可導(dǎo)入:
$ touch local-addons/my_library/__init__.py
- 為Odoo添加一個(gè)最小化的模塊聲明來(lái)將其作為一個(gè)插件模塊。創(chuàng)建manifest.py 文件并添加如下行:
{'name': 'My Library'}
- 啟動(dòng)你的Odoo實(shí)例,將你的插件目錄添加到插件路徑中:
$ odoo/odoo-bin --addons-path=odoo/addon/,local-addons/
> ??如果在該Odoo命令中添加了 --save 選項(xiàng),插件路徑會(huì)被保存到配置文件中。下次你啟動(dòng)服務(wù)時(shí),如果沒(méi)有提供插件路徑選項(xiàng)的話,就會(huì)使用它。
- 讓這個(gè)新模塊在Odoo中可用;使用管理員登錄Odoo,啟動(dòng)開(kāi)發(fā)者模式,然后在Apps頂級(jí)菜單中選擇Update Apps List?,F(xiàn)在Odoo就識(shí)別到了我們的模塊了。
- 選擇頂部的Apps菜單,在右上方的搜索欄中,刪除默認(rèn)的應(yīng)用過(guò)濾器并搜索my_library,點(diǎn)擊它的Install按鈕,就完成了安裝。
運(yùn)行原理...
Odoo模塊是一個(gè)包含代碼文件及其它資源的目錄。所使用的目錄名為模塊的技術(shù)名稱(chēng)。模塊聲明中的 name 鍵對(duì)應(yīng)其標(biāo)題。
manifest.py文件是模塊的聲明。它包含一個(gè)帶有模塊元數(shù)據(jù)的Python字典,有分類(lèi)、版本、它所依賴(lài)的模塊以及一系列它將要加載的數(shù)據(jù)文件。在這一節(jié)中,我們使用了最簡(jiǎn)化的聲明文件,但在真實(shí)的模塊中,我們將使用其它的重要爭(zhēng)名。這將在下一節(jié)完成插件模塊的聲明是進(jìn)行討論。
模塊目錄必須是Python可導(dǎo)入的,因此即便目錄為空也要添加一個(gè)init.py 文件。要載入一個(gè)模塊,Odoo模塊將會(huì)導(dǎo)入它。這會(huì)導(dǎo)致init.py文件中的代碼被執(zhí)行,它作為運(yùn)行該模塊Python代碼的一個(gè)入口。因此,它通常會(huì)包含加載模塊Python文件及子模塊的一些重要聲明語(yǔ)句。
已識(shí)別模塊可通過(guò)命令行使用--init或-i選項(xiàng)直接安裝。這一模塊列表在提供插件路徑新建數(shù)據(jù)庫(kù)時(shí)獲取到的模塊進(jìn)行初始化設(shè)置。可通過(guò)Update Module List菜單更新已有數(shù)據(jù)庫(kù)。
完成插件模塊的聲明
聲明文件對(duì)于Odoo模塊非常重要。它包含插件模塊重要的元數(shù)據(jù)并聲明了應(yīng)加載的數(shù)據(jù)文件。
準(zhǔn)備工作
我們應(yīng)當(dāng)有一個(gè)包含manifest.py聲明文件的模塊來(lái)進(jìn)行操作。你可能要按前一節(jié)的步驟來(lái)提供一個(gè)可以操作的模塊。
如何操作...
我們?yōu)檫@個(gè)插件模塊添加一個(gè)聲明文件和一個(gè)圖標(biāo):
- 以最相關(guān)的鍵名創(chuàng)建一個(gè)聲明文件,編輯模塊的manifest.py文件至內(nèi)容如下:
{
'name': "My library",
'summary': "Manage books easily",
'description': """Long description""",
'author': "Your name",
'website': "http://www.example.com",
'category': 'Uncategorized',
'version': '12.0.1',
'depends': ['base'],
'data': ['views.xml'],
'demo': ['demo.xml'],
}
- 為該模塊添加一個(gè)圖標(biāo),需選擇一個(gè)PNG圖像來(lái)供使用并將其拷貝至static/description/icon.png
運(yùn)行原理...
聲明文件中的內(nèi)容是一個(gè)常規(guī)的Python字典,包含鍵和值。我們的示例聲明中包含了大部分相關(guān)的鍵名:
- name:這是該模塊的標(biāo)題。
- summary:這是一個(gè)單行描述的副標(biāo)題。
- description:這是一個(gè)以普通文本或重構(gòu)文本(RST)格式編寫(xiě)的長(zhǎng)描述。通常放在三個(gè)引號(hào)中,Python中使用三個(gè)引號(hào)來(lái)界定多行文本。RST的快速入門(mén)指南請(qǐng)見(jiàn)http://docutils.sourceforge.net/docs/user/rst/quickstart.html。
- author:是一個(gè)作者姓名的字符串。如果有多個(gè)作者的話,一般使用逗號(hào)來(lái)進(jìn)行分隔,但注意它仍應(yīng)是一個(gè)字符串,而非Python列表。
- website:這個(gè) URL 可供人們?cè)L問(wèn)來(lái)了解模塊或作者的更多信息。
- category:這用于在網(wǎng)絡(luò)上組織模塊。標(biāo)準(zhǔn)的分類(lèi)名稱(chēng)列表請(qǐng)見(jiàn)https://github.com/odoo/odoo/blob/12.0/odoo/addons/base/data/ir_module_category_data.xml。但也可以定義這些名稱(chēng)以外的分類(lèi)名稱(chēng)。
- version:這是該模塊的版本號(hào)。可由Odoo應(yīng)用商店用于檢測(cè)已安裝模塊的新版本。如果版本號(hào)沒(méi)有以O(shè)doo目標(biāo)版本號(hào)(如12.0)開(kāi)始,會(huì)進(jìn)行自動(dòng)添加。但是,如果你顯式的聲明Odoo目標(biāo)版本號(hào)信息量會(huì)充足,比如用12.0.1.0.0或12.0.1.0來(lái)替代1.0.0或1.0。
- depends:這是該模塊所直接依賴(lài)的模塊技術(shù)名稱(chēng)列表。如果你的模塊不依賴(lài)于任何其它插件模塊,那么應(yīng)至少添加一個(gè)base模塊。別忘記包含這個(gè)模塊所引用的XML ID、視圖或模塊的定義模塊。那樣會(huì)確保它們以正確的順序進(jìn)行加載,避免難以調(diào)試的錯(cuò)誤。
- data:這是在模塊安裝或升級(jí)時(shí)需加載數(shù)據(jù)文件的相對(duì)路徑列表。這些路徑相對(duì)于模塊的根目錄。通常,這些是XML和CSV文件,但也可以使用YAML格式的數(shù)據(jù)文件。這些內(nèi)容會(huì)在第七章 模塊數(shù)據(jù)中深入討論。
- demo:這是加載演示數(shù)據(jù)的文件的相對(duì)路徑列表。僅在創(chuàng)建數(shù)據(jù)庫(kù)時(shí)啟用了Demo Data標(biāo)記時(shí)都會(huì)進(jìn)行加載。
模塊圖標(biāo)使用的圖像是位于static/description/icon.png的一個(gè)PNG文件。
小貼士:Odoo的大版本一般會(huì)有較大的變化,因此如不進(jìn)行轉(zhuǎn)化或遷移操作的話,一個(gè)大版本中構(gòu)建的模塊不大可能與下一個(gè)版本進(jìn)行兼容。因此,在安裝模塊前確定Odoo的目標(biāo)版本號(hào)就非常的重要了。
擴(kuò)展內(nèi)容
也可以使用一個(gè)單獨(dú)的描述文件來(lái)替代模塊聲明中的長(zhǎng)描述。自8.0版起,可通過(guò)后綴名為 .txt、.rst或.md(Markdown)的README文件來(lái)進(jìn)行替換。此外,可在模塊中包含一個(gè)description/index.html文件。
這個(gè)HTML描述會(huì)覆蓋掉聲明文件中所定義的描述。
還有一些常用的其它鍵名:
- licence:默認(rèn)值為L(zhǎng)GPL-3。這一標(biāo)識(shí)符用于模塊對(duì)外使用的證書(shū)。其它可用的證書(shū)有AGPL-3、Odoo自有證書(shū)v1.0(多用于付費(fèi)應(yīng)用)以及其它OSI核準(zhǔn)的證書(shū)。
- application:如果為T(mén)rue,模塊作為應(yīng)用列出。通常這用于一個(gè)功能區(qū)的中央模塊。
- auto_install:若為T(mén)rue,表示這是一個(gè)膠水模塊,在它所有的依賴(lài)模塊安裝后會(huì)被自動(dòng)安裝。
- installable:若為T(mén)rue(默認(rèn)值),表示該模塊可以進(jìn)行安裝。
- external_dependencies:有些Odoo模塊內(nèi)部使用了Python/bin庫(kù)。如果你的模塊使用了這些庫(kù),需要在這里進(jìn)行添加。如果列出的模塊在你的主機(jī)上沒(méi)有安裝的話則會(huì)停止該模塊的安裝。
- {pre_init, post_init, uninstall}_hook:這是在安裝/卸載時(shí)調(diào)用的Python函數(shù)鉤子。更多詳細(xì)示例,請(qǐng)見(jiàn)第九章 高級(jí)服務(wù)端開(kāi)發(fā)技巧。
組織插件模塊文件結(jié)構(gòu)
一個(gè)插件模塊包含代碼及其它資源文件,如XML文件和圖像。大多數(shù)這些文件,我們都可以自由選擇其在插件目錄中的存放位置。
但是,Odoo使用了一些模塊結(jié)構(gòu)的慣例,建議遵循這一慣例。
準(zhǔn)備工作
我們應(yīng)當(dāng)有一個(gè)插件模塊目錄,其中僅包含init.py和manifest.py文件。本節(jié)中,我們假定目錄為local-addons/my_library。
如何操作...
執(zhí)行如下步驟來(lái)為該插件模塊創(chuàng)建基本結(jié)構(gòu):
- 為代碼文件創(chuàng)建目錄:
$ cd local-addons/my_library
$ mkdir models
$ touch models/__init__.py
$ mkdir controllers
$ touch controllers/__init__.py
$ mkdir views
$ mkdir security
$ mkdir data
$ mkdir demo
$ mkdir i18n
- 編輯模塊的頂級(jí) init.py文件,這樣子目錄中的代碼會(huì)被加載到:
from . import models
from . import controllers
這會(huì)給我們一個(gè)包含最常用目錄的入手結(jié)構(gòu),類(lèi)似下面這樣:
.
├── __init__.py
├── __manifest__.py
├── controllers
│ └── __init__.py
├── data
├── demo
├── i18n
├── models
│ └── __init__.py
├── static
│ └── description
│ └── icon.png
└── views
運(yùn)行原理...
為大家普及一下背景,Odoo插件模塊可以有三種類(lèi)型文件:
- Python代碼由 init.py加載,通過(guò)該文件導(dǎo)入.py文件及代碼子目錄。子目錄中包含的Python代碼,再由其內(nèi)部的init.py導(dǎo)入。
- 模塊聲明文件manifest.py中data和demo鍵名所聲明供加載的數(shù)據(jù)文件通常是用戶界面、fixture數(shù)據(jù)和演示數(shù)據(jù)中會(huì)使用到的XML和CSV文件。還可使用YAML文件,可以包含一些模塊加載時(shí)運(yùn)行的過(guò)程指令,例如,通過(guò)程序生成或更新記錄而非在XML文件中加入數(shù)據(jù)。
- 網(wǎng)頁(yè)資源,如JavaScript代碼和庫(kù)、CSS、SASS和QWeb/HTML模板。這些文件用于在 UI 元素中構(gòu)建UI組成部分及管理用戶動(dòng)作。它們通過(guò)繼承主模板的XML文件來(lái)進(jìn)行聲明,用于為網(wǎng)頁(yè)客戶端或網(wǎng)站頁(yè)面添加這些資源。
插件文件以如下目錄進(jìn)行組織:
- models/包含后端代碼文件,用于創(chuàng)建模型及其業(yè)務(wù)邏輯。推薦每個(gè)模型一個(gè)文件并使用與模型相同的名稱(chēng),例如 library.book模型的對(duì)應(yīng)文件為library_book.py。這些在第五章 應(yīng)用模型中會(huì)進(jìn)行深入講解。
- views/包含用于用戶界面的XML文件,包含動(dòng)作、表單、列表等等。類(lèi)似于模型,建議每個(gè)模型一個(gè)文件。網(wǎng)站模塊的文件名通常以_template后綴進(jìn)行結(jié)尾。后端視圖在第十章 后端視圖中講解,網(wǎng)站視圖在第十五章 CMS網(wǎng)站開(kāi)發(fā)中進(jìn)行講解。
- data/包含模塊初始數(shù)據(jù)的其它數(shù)據(jù)文件。數(shù)據(jù)文件在第七章 模塊數(shù)據(jù)中進(jìn)行講解。
- demo/包含帶演示數(shù)據(jù)的數(shù)據(jù)文件,對(duì)于測(cè)試、培訓(xùn)或模塊評(píng)測(cè)都非常有用。
- Odoo會(huì)在i18n/中查找.pot及.po翻譯文件。更多詳情參見(jiàn)第十二章 國(guó)際化。這些文件無(wú)需在聲明文件中提及。
- security/包含定義訪問(wèn)控制列表的數(shù)據(jù)文件,通常是一個(gè)ir.model.access.csv文件,也可以是一個(gè)XML文件,用于定義權(quán)限組及行級(jí)權(quán)限的記錄規(guī)則。參見(jiàn)第十一章 權(quán)限安全來(lái)獲取更多內(nèi)容。
- controllers/包含網(wǎng)站控制器的代碼文件,用于為模塊提供各種功能。網(wǎng)頁(yè)控制器在第十四章 網(wǎng)頁(yè)服務(wù)端開(kāi)發(fā)中進(jìn)行講解。
- static/用于放置所有的網(wǎng)頁(yè)資源。和其它目錄不同,該目錄名不只是一種慣例。這一目錄中的文件無(wú)需用戶登錄即可對(duì)外提供訪問(wèn)。該目錄多包含JavaScript、樣式表、圖像等文件。它們無(wú)需在模塊聲明文件中進(jìn)行提及,但需要在網(wǎng)頁(yè)模板中引用。這會(huì)在第十五章 CMS網(wǎng)站開(kāi)發(fā)中進(jìn)行討論。
小貼士:在向模塊添加新文件時(shí),不要忘記在manifest.py(數(shù)據(jù)文件)或init.py(代碼文件)文件中進(jìn)行聲明,否則會(huì)忽略這些文件而不進(jìn)行加載。
添加模型
數(shù)據(jù)結(jié)構(gòu)中定義的模型會(huì)用于我們的業(yè)務(wù)應(yīng)用。這一節(jié)向讀者展示如何為模塊添加基本模型。
在我們的示例中,希望對(duì)圖書(shū)館的書(shū)籍進(jìn)行管理。那么,我們需要?jiǎng)?chuàng)建一個(gè)代表書(shū)籍的模型。每本書(shū)包含書(shū)名及一名或多名作者。
準(zhǔn)備工作
我們需要有一個(gè)模塊來(lái)進(jìn)行操作。如果你按照本章第一節(jié)創(chuàng)建和安裝一個(gè)新的插件模塊操作的話,則會(huì)有一個(gè)名為my_library的空模塊。我們將使用它來(lái)做進(jìn)一步講解。
如何操作...
要添加新模型,我們需要添加一個(gè)Python文件來(lái)描述它,然后升級(jí)插件模塊(如未安裝則執(zhí)行安裝)。以下使用的路徑為我們的插件模塊目錄中的相對(duì)路徑(例如,~/odoo-dev/local-addons/my_library/):
- 為模塊添加一個(gè) Python 文件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'
)
- 在模塊中添加一個(gè)Python初始化文件models/init.py來(lái)加載代碼,內(nèi)容如下:
from . import library_book
- 編輯模塊的Python初始化文件來(lái)在模塊中加載models/目錄:
from . import models
- 從命令行或用戶界面中的Apps菜單中升級(jí)該Odoo模塊。如果你在升級(jí)模塊時(shí)仔細(xì)查看服務(wù)日志的話,會(huì)看到如下行:
odoo.modules.registry: module my_library: creating or updating database table
然后,就可以在我們的Odoo實(shí)例中使用這一新的library.book模型了。有兩種方式來(lái)查看我們的模型是否在數(shù)據(jù)庫(kù)中進(jìn)行了添加。
第一種方式是你可以在用戶界面中進(jìn)行查看。激活開(kāi)發(fā)者工具,然后打開(kāi)菜單Settings>Technical>Database Structure>Models。然后在那里搜索library.book模型。
第二種方式是查看PostgreSQL數(shù)據(jù)庫(kù)中的表數(shù)據(jù)。你可以在數(shù)據(jù)庫(kù)中搜索library_book數(shù)據(jù)表。在下面的代碼示例中,我們使用了test-12.0作為數(shù)據(jù)庫(kù)。但是你可以修改為你自己的數(shù)據(jù)庫(kù)名:
$ psql test-12.0
test-12.0# \d library_book;
運(yùn)行原理...
第1步中我們?cè)谀K中創(chuàng)建一個(gè)了一個(gè)Python文件。
Odoo框架有著其自己的ORM框架。這一ORM對(duì)PostgreSQL數(shù)據(jù)庫(kù)進(jìn)行了抽象。通過(guò)繼承Odoo Python類(lèi)Model,我們可以創(chuàng)建自己的模型(數(shù)據(jù)表)。在定義新模型時(shí),也將其加入到了中央模型倉(cāng)庫(kù)中。這讓其它模塊在之后對(duì)其進(jìn)行修改變得更為容易。
模型有一些以下劃線為前綴的通用屬性。最重要的一個(gè)是_name,它提供了一個(gè)唯一內(nèi)部標(biāo)識(shí)符來(lái)在Odoo實(shí)例中進(jìn)行使用。ORM會(huì)根據(jù)這個(gè)屬性來(lái)生成數(shù)據(jù)表。本節(jié)中,我們使用了_name = 'library.book'?;谶@一屬性,該ORM框架會(huì)創(chuàng)建一個(gè)名為library_book的新數(shù)據(jù)表。注意ORM在創(chuàng)建新表的名稱(chēng)時(shí)會(huì)通過(guò)將_name屬性中的. 替換為 _ 。
模型字段以類(lèi)型屬性的方式進(jìn)行定義。我們首先以Char類(lèi)型定義了name字段。模型中有這一字段會(huì)非常方便,因?yàn)槟J(rèn)在其它模型中引用該模型時(shí),它會(huì)用作記錄描述。
我們還使用了一個(gè)關(guān)聯(lián)字段的示例author_ids。這在圖書(shū)和其作者之前建立了一個(gè)多對(duì)多的關(guān)聯(lián)。一本書(shū)可以有多個(gè)作者,而每個(gè)作者也可以編寫(xiě)多本書(shū)。
有關(guān)模型有很多可以討論的地方,我們將在第五章 應(yīng)用模型中進(jìn)行深度講解。
接下來(lái),我們必須讓我們的模塊可以識(shí)別到這一新的Python文件。這通過(guò)init.py文件來(lái)實(shí)現(xiàn)。因?yàn)閷⒋a放在了models/子目錄內(nèi),我們需要前述的init.py 文件來(lái)導(dǎo)入該目錄,其中又應(yīng)包含另一個(gè)init.py文件,在其中導(dǎo)入那里的每一個(gè)代碼文件(本例中只有一個(gè)文件)。
對(duì)Odoo模型的修改通過(guò)升級(jí)該模型來(lái)啟用。Odoo服務(wù)會(huì)處理由模型類(lèi)到數(shù)據(jù)庫(kù)結(jié)構(gòu)變化的轉(zhuǎn)換。
雖然此處沒(méi)有提供示例,業(yè)務(wù)邏輯也可以在這些Python文件中進(jìn)行添加,或通過(guò)對(duì)模型類(lèi)添加新的方法,或繼承已有方法,如create() 或 write()。這在第六章 基本服務(wù)端部署中進(jìn)行討論。
添加菜單項(xiàng)和視圖
在有了我們的數(shù)據(jù)結(jié)構(gòu)所需的模型之后,我們希望用戶可以通過(guò)用戶界面與它們進(jìn)行交互。本節(jié)基于上一節(jié)的圖書(shū)模型進(jìn)行創(chuàng)建,添加一個(gè)菜單項(xiàng)來(lái)顯示一個(gè)包含列表和表單視圖的用戶界面。
準(zhǔn)備工作
需要有實(shí)現(xiàn)library.book模型的插件模塊,這在上一節(jié)中已經(jīng)提供到。使用的路徑為相對(duì)插件模塊所處位置的相對(duì)路徑(如~/odoo-dev/local-addons/my_library/)。
如何操作...
要添加一個(gè)視圖,我們將添加一個(gè)XML文件,其中包含對(duì)于模塊的定義。因其是一個(gè)新模型,我們還應(yīng)添加一個(gè)菜單選項(xiàng)來(lái)讓用戶可以訪問(wèn)它。
注意下述步驟的順序也是很重要的,因?yàn)槠渌囊恍?huì)引用到在之前步驟中定義的ID:
- 創(chuàng)建一個(gè)XML文件views/library_book.xml來(lái)添加描述用戶界面的數(shù)據(jù)記錄:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Data records go here -->
</odoo>
- 在插件模塊聲明文件manifest.py中添加新的數(shù)據(jù)文件,通過(guò)views/library_book.xml來(lái)進(jìn)行添加:
{
'name': "My Library",
'summary': "Manage books easily",
'depends': ['base'],
'data': ['views/library_book.xml'],
}
- 在library_book.xml文件中添加打開(kāi)視圖的動(dòng)作:
<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_type">form</field>
<field name="view_mode">tree,form</field>
</record>
- 在library_book.xml文件中添加菜單項(xiàng),讓其對(duì)用戶可見(jiàn):
<menuitem name="My Library" id="libray_base_menu" />
<menuitem name="Books" id="library_book_menu"
parent="libray_base_menu" action="library_book_action" />
- 在library_book.xml文件中添加一個(gè)自定義表單視圖:
<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>
- 在library_book.xml文件中添加自定義樹(shù)狀(列表)視圖:
<field name="name">Libray 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>
- 在library_book.xml文件中添加自定義搜索選項(xiàng):
<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 Author"
name="withou_author"
domain="[{'author_ids', '=', False}]" />
</search>
</field>
</record>
從版本號(hào)12開(kāi)始, admin 用戶必須要獲取相應(yīng)的訪問(wèn)權(quán)限才能在用戶界面中訪問(wèn)我們的模型。在沒(méi)有賦予相應(yīng)的訪問(wèn)權(quán)限時(shí),Odoo是不會(huì)顯示你的菜單和視圖的在下一節(jié)中,我們將為我們的模型添加訪問(wèn)權(quán)限,在那之后你才可以通過(guò)admin用戶來(lái)查看這些菜單和視圖。
以超級(jí)用戶訪問(wèn) Odoo
通過(guò)將admin轉(zhuǎn)換為超級(jí)用戶superuser,你就可以不受訪問(wèn)權(quán)限的限制,因此無(wú)需授予訪問(wèn)權(quán)限即可訪問(wèn)所有菜單和視圖。要將admin用戶轉(zhuǎn)換為superuser,先激活開(kāi)發(fā)者模式。然后在開(kāi)發(fā)者工具選項(xiàng)中,點(diǎn)擊Become super user選項(xiàng)。
以下截圖供您參考:

在成為超級(jí)用戶之后,你的菜單會(huì)顯示一個(gè)條狀背景,如下圖所示:

這時(shí)如果你試著升級(jí)模塊,則會(huì)看到一個(gè)新的菜單選項(xiàng)(可能會(huì)需要刷新瀏覽器)。點(diǎn)擊Books菜單會(huì)打開(kāi)圖書(shū)模型的列表視圖,如下圖所示:

運(yùn)行原理...
在底層中,用戶界面由存儲(chǔ)在特定模型中的記錄所定義。前兩步中創(chuàng)建了一個(gè)空的XML文件來(lái)定義待加載的記錄,然后將它們添加到模型的數(shù)據(jù)文件列表中來(lái)供安裝。
數(shù)據(jù)文件可以放在該模型目錄中的任意位置,但按照習(xí)慣用戶界面的數(shù)據(jù)文件在views/子目錄中定義。通常,這些文件的名稱(chēng)是基于模型的名稱(chēng)的。本例中,我們?yōu)閘ibrary.book模型創(chuàng)建用戶界面,因此我們創(chuàng)建了views/library_book.xml文件。
下一步是定義在客戶端主區(qū)域用戶界面中顯示的窗口動(dòng)作。該動(dòng)作有一個(gè)由 res_model,定義的目標(biāo)模型,name屬性用于在用戶打開(kāi)動(dòng)作時(shí)向用戶所顯示的標(biāo)題。這些都是基本屬性。窗口動(dòng)作還支持其它屬性,讓我們對(duì)視圖渲染方式擁有更多的控制,比如顯示什么視圖,為可用的記錄添加過(guò)濾器或設(shè)置默認(rèn)值。這些會(huì)在第十章 后端視圖中進(jìn)行討論。
通常,數(shù)據(jù)記錄使用<record>標(biāo)簽定義,在本例中我們?yōu)閕r.actions.act_window模型創(chuàng)建了一條記錄。這會(huì)創(chuàng)建窗口動(dòng)作。
類(lèi)似地,菜單項(xiàng)存儲(chǔ)在ir.ui.menu模型中,我們可以使用<record>標(biāo)簽來(lái)進(jìn)行創(chuàng)建。但是在Odoo中有一個(gè)名為<menuitem>的快捷標(biāo)簽,因此我們?cè)诒纠羞M(jìn)行了使用。
以下是菜單項(xiàng)的主要屬性:
- name:這是要顯示的菜單項(xiàng)文本。
- action:這是要執(zhí)行的動(dòng)作的標(biāo)識(shí)符。我們使用前一步中所創(chuàng)建的窗口動(dòng)作ID。
- sequence:這用于設(shè)置同級(jí)菜單項(xiàng)的顯示順序。
- parent:這是父級(jí)菜單項(xiàng)的標(biāo)識(shí)符。本例中的菜單項(xiàng)沒(méi)有父級(jí),即它會(huì)顯示在頂級(jí)菜單中。
至此,我們還沒(méi)有在模型中定義任何視圖。但是,如果這時(shí)你升級(jí)了該模型,Odoo會(huì)自動(dòng)地實(shí)時(shí)為你創(chuàng)建視圖??墒?,我們一定會(huì)想要控制視圖的展示內(nèi)容,因此,在接下來(lái)的兩步中創(chuàng)建了一個(gè)表單視圖和一個(gè)樹(shù)狀視圖。
這兩個(gè)視圖通過(guò) ir.ui.view 模型上的一條記錄進(jìn)行定義。我們所使用的屬性如下:
-
name:這是標(biāo)識(shí)視圖的標(biāo)題。在Odoo的源碼中,你會(huì)發(fā)現(xiàn)這里重復(fù)使用了XML ID,但是你完全可以添加一個(gè)更易于閱讀的名稱(chēng)作為標(biāo)題。
小貼士:如果省略了name字段,Odoo會(huì)使用模型名稱(chēng)及視圖類(lèi)型來(lái)生成一個(gè)。對(duì)于新模型的標(biāo)準(zhǔn)視圖這完全沒(méi)有問(wèn)題。在繼承視圖時(shí)建議使用一個(gè)更具說(shuō)明性的名稱(chēng),因?yàn)檫@會(huì)讓你在Odoo用戶界面上查找具體視圖時(shí)更為方便。
model:這是目標(biāo)模型的內(nèi)部標(biāo)識(shí)符,和_name屬性中的所定義的名稱(chēng)一致。
arch:這是視圖結(jié)構(gòu),實(shí)際定義結(jié)構(gòu)的地方。這里不同類(lèi)型的視圖會(huì)有不同。
表單視圖在頂級(jí)<form>元素中定義,它的畫(huà)布是一個(gè)兩列網(wǎng)格。在表單內(nèi),<group>元素用于在垂直方向上編排字段。兩個(gè)組會(huì)生成包含<field>元素所定義字段的兩個(gè)列。字段根據(jù)數(shù)據(jù)類(lèi)型使用其默認(rèn)組件,但可以使用widget屬性來(lái)指定所要使用的組件。
樹(shù)狀視圖要簡(jiǎn)單些,它們以包含用于各列中顯示的<field>元素的頂級(jí)<tree>元素定義。
最后,我們添加了搜索視圖來(lái)在右上角的搜索框中擴(kuò)展搜索選項(xiàng)。在頂級(jí)的<search>標(biāo)簽中,可以包含<field>和<filter>元素。字段元素是在搜索視圖中可用于搜索的其它字段。過(guò)濾器元素為可通過(guò)點(diǎn)擊激活的預(yù)置過(guò)濾條件。這些話題會(huì)在第十章 后端視圖中進(jìn)行討論。
添加訪問(wèn)權(quán)限
在添加新的數(shù)據(jù)模型時(shí),你需要定義誰(shuí)可以創(chuàng)建、讀取、更新和刪除記錄。在創(chuàng)建一個(gè)全新的應(yīng)用時(shí),這可能還包含新的用戶組的定義。因此,如果用戶沒(méi)有訪問(wèn)權(quán)限的話,Odoo則不會(huì)該顯示菜單和視圖。在上一節(jié)中,我們將admin用戶轉(zhuǎn)換為超級(jí)用戶來(lái)訪問(wèn)這個(gè)菜單。在學(xué)完本節(jié)后,你就可以直接以admin用戶來(lái)訪問(wèn)我們圖書(shū)模塊的菜單和視圖了。
這一節(jié)使用上一節(jié)中的定義的圖書(shū)模型,會(huì)定義一個(gè)用戶安全組來(lái)控制誰(shuí)能夠訪問(wèn)或修改書(shū)籍記錄。
準(zhǔn)備工作
我們會(huì)需要上一節(jié)中實(shí)現(xiàn)了library.book模型的插件模塊,因?yàn)樵谶@一節(jié)我們會(huì)為其添加權(quán)限規(guī)則。使用的是插件模塊所在位置(例如~/odoo-dev/local-addons/my_library/)的相對(duì)路徑。
如何操作...
我們要在本節(jié)中添加的安全規(guī)則如下:
- 所有人均可閱讀圖書(shū)記錄
- 名為L(zhǎng)ibrarians的新用戶組擁有創(chuàng)建、閱讀、更新和刪除書(shū)籍記錄的權(quán)限
要進(jìn)行實(shí)現(xiàn),我們需要執(zhí)行如下步驟:
- 創(chuàng)建一個(gè)名為security/groups.xml的文件并添加如下內(nèi)容:
<?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>
- 添加一個(gè)名為security/ir.model.access.csv的文件并加入如下內(nèi)容:
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中添加這兩個(gè)數(shù)據(jù)文件:
# ...
'data': [
'security/groups.xml',
'security/ir.model.access.csv',
'views/library_book.xml'
],
# ...
在實(shí)例中更新插件后即可使用新定義的權(quán)限規(guī)則了。
運(yùn)行原理...
我們提供了兩個(gè)新數(shù)據(jù)文件并添加到了插件模塊的聲明文件中,這樣安裝或升級(jí)該模塊時(shí)會(huì)在數(shù)據(jù)庫(kù)中加載它們:
- security/groups.xml通過(guò)創(chuàng)建一條res.groups記錄來(lái)定義一個(gè)新權(quán)限組。我們通過(guò)admin用戶的引用ID base.user_admin為其授予了Librarians的權(quán)限,這樣admin用戶將擁有l(wèi)ibrary.book模型的權(quán)限。
- ir.model.access.csv通過(guò)組來(lái)關(guān)聯(lián)模型的權(quán)限。第一行g(shù)roup_id:id列為空,表示該規(guī)則適用于所有人。最后一行授予了我們剛剛創(chuàng)建的組的成員所有權(quán)限:
小貼士:聲明文件中data版塊內(nèi)文件的順序非常重要,創(chuàng)建權(quán)限組的文件必須要在列出安全權(quán)限的文件之前加載,因?yàn)榘踩珯?quán)限的定義依賴(lài)于組的存在。因?yàn)橐晥D可具體到權(quán)限組,我們推薦將組的定義文件放在該列表中會(huì)更為保險(xiǎn)。
其它內(nèi)容
- 有關(guān)權(quán)限本書(shū)有單獨(dú)的一章。更多有關(guān)權(quán)限的內(nèi)容,參見(jiàn)第十一章 權(quán)限安全。
使用腳手架命令來(lái)創(chuàng)建模塊
在新建 Odoo 模塊時(shí),需要設(shè)置一些范本代碼。為幫助大家快速新建模塊,Odoo提供了scaffold(腳手架)命令。
本節(jié)向你展示如何使用scaffold命令新建一個(gè)模塊,它會(huì)創(chuàng)建一個(gè)目錄和文件結(jié)構(gòu)來(lái)供使用。
準(zhǔn)備工作
我們將在一個(gè)自定義模塊目錄中新建一個(gè)插件模塊,因此需要已安裝Odoo并且給自定模塊一個(gè)目錄。假定Odoo安裝的位置為/odoo-dev/odoo,我們的自定義模塊會(huì)放置在/odoo-dev/local-addons目錄中。
如何操作...
我們將使用scaffold命令來(lái)創(chuàng)建樣例代碼。按照給定的步驟來(lái)使用scaffold命令新建一個(gè)模塊:
- 更改工作目錄到想要放置模塊的地方。它可以是你所選擇的任意目錄,但需要在一個(gè)插件路徑中才可進(jìn)行使用。按照我們?cè)谇懊嫘」?jié)中所選擇的目錄,應(yīng)該是這樣的:
$ cd ~/odoo-dev/local-addons
- 為這個(gè)新模塊選擇一個(gè)技術(shù)名稱(chēng),并使用scaffold命令來(lái)創(chuàng)建它。本例中,我們選擇的是my_module:
$ ~/odoo-dev/odoo/odoo-bin scaffold my_module
- 編輯默認(rèn)聲明文件manifest.py并修改相應(yīng)的值。你一定會(huì)想要修改name鍵中的模塊標(biāo)題。
以下是生成的插件模塊的結(jié)構(gòu):
$ tree my_module/
my_module/
├── controllers
│ ├── controllers.py
│ └── __init__.py
├── demo
│ └── demo.xml
├── __init__.py
├── __manifest__.py
├── models
│ ├── __init__.py
│ └── models.py
├── security
│ └── ir.model.access.csv
└── views
├── templates.xml
└── views.xml
5 directories, 10 files
現(xiàn)在你應(yīng)編輯各個(gè)生成的文件來(lái)適應(yīng)你對(duì)新模塊的需求。
運(yùn)行原理...
scaffold命令創(chuàng)建基于一個(gè)模板的新模塊結(jié)構(gòu)。
默認(rèn),這個(gè)新模塊在當(dāng)前工作目錄中進(jìn)行創(chuàng)建,但我們也可以指定一個(gè)目錄來(lái)創(chuàng)建該模塊,將其作為一個(gè)額外的參數(shù)進(jìn)行傳遞。
參考如下示例:
$ ~/odoo-dev/odoo/odoo-bin scaffold my_module ~/odoo-dev/local-addons
此處使用了一個(gè)默認(rèn)模板,但也可以為網(wǎng)站主題編寫(xiě)的主題模板??梢允褂?-t選項(xiàng)來(lái)選擇一個(gè)指定的模板。我們也可以使用包含模板的一個(gè)目錄來(lái)作為路徑。
這表示我們可以通過(guò)scaffold命令來(lái)使用我們自己的模板。內(nèi)置的主題可作為一個(gè)向?qū)?,可以?/odoo/cli/templates這個(gè)Odoo子目錄中找到。我們可以用類(lèi)似下面的命令來(lái)使用我們自己的模板:
$ ~/odoo-dev/odoo/odoo-bin scaffold -t path/to/template my_module