????????可以參考著名的http://todomvc.com/ 項(xiàng)目。
????????我們將創(chuàng)建一個(gè)簡(jiǎn)單的 ToDo 應(yīng)用,它將允許我們添加新的任務(wù),當(dāng)任務(wù)完成的時(shí)候標(biāo)記它們,并最終清除所有的已完成任務(wù)的列表。
????????Odoo遵循 MVC-like 架構(gòu)設(shè)計(jì),當(dāng)實(shí)現(xiàn) To-Do 應(yīng)用的時(shí)候,我們會(huì)接觸不同的層。
模型層,定義app 的數(shù)據(jù)結(jié)構(gòu)
視圖層,描述用戶界面
控制器層,支持應(yīng)用的業(yè)務(wù)邏輯
2.1.基本概念
2.1.1.了解應(yīng)用程序和模塊
????????在Odoo中,經(jīng)常聽見模塊(modules)和應(yīng)用程序(application)。那么,它們有什么區(qū)別呢?
????????模塊元件是Odoo應(yīng)用程序的組成塊。一個(gè)模塊可以將新功能添加到 Odoo,或修改現(xiàn)有的功能。 它是一個(gè)包含名為manifest.py的清單或描述符文件的目錄,再加上實(shí)現(xiàn)其功能的其余文件。
????????應(yīng)用程序是將主要功能添加到Odoo的方式。他們?yōu)楹诵墓δ茉?,如?huì)計(jì)或人力資源,其它的模塊在此基礎(chǔ)上修改或擴(kuò)展功能。正因?yàn)槿绱?,他們?cè)贠doo應(yīng)用程序菜單中高亮顯示。
????????如果您的模塊很復(fù)雜,并將新的或重大的功能添加到 Odoo,您可以考慮將它創(chuàng)建為應(yīng)用程序。如果您的模塊只是對(duì)現(xiàn)有的 Odoo 中的功能進(jìn)行更改,則可能不需要將它創(chuàng)建為應(yīng)用程序。
????????在清單中定義模塊是否是應(yīng)用程序。技術(shù)上它在模塊使用上,沒有任何的影響。它只是在應(yīng)用程序清單中高亮顯示。
2.1.2.修改和擴(kuò)展模塊
????????在示例中,我們要記住,在新模塊創(chuàng)建時(shí),要盡可能少的使用依賴關(guān)系。然而,這不是常見情況。大多數(shù)情況下,我們將修改或擴(kuò)展現(xiàn)有的模塊。
????????一般情況下,通過直接更改它們的源代碼修改現(xiàn)有模塊的功能是一個(gè)很糟糕的方法。對(duì)于 Odoo 提供的官方模塊,尤其如此。如果這樣做,你不能明確的區(qū)分原始模塊代碼和修改,并且這使它難以升級(jí),因?yàn)樯?jí)會(huì)覆蓋所做的修改。相反,我們應(yīng)該創(chuàng)建一個(gè)額外的模塊,去實(shí)現(xiàn)我們需要改變或者增加的功能。事實(shí)上,Odoo 的主要優(yōu)勢(shì)之一是繼承機(jī)制,允許自定義模塊擴(kuò)展現(xiàn)有模塊,無論是官方的還是社區(qū)的。
????????繼承可以是任意一個(gè)層次︰ 數(shù)據(jù)模型、業(yè)務(wù)邏輯和用戶界面層。一旦我們可以輕松的創(chuàng)建一個(gè)新的模塊,我們可以深入的學(xué)習(xí)繼承機(jī)制。
2.1.3.創(chuàng)建模塊的基本框架
????????Odoo包括一個(gè)scaffold命令來自動(dòng)創(chuàng)建一個(gè)新的模塊目錄,其基本結(jié)構(gòu)已經(jīng)就位。 你可以用下面的命令來了解更多。
$ ~/odoo-dev/odoo/odoo-bin scaffold --help
????????在處理下一個(gè)模塊時(shí),您可能想要記住這一點(diǎn),但是我們現(xiàn)在不會(huì)使用它,因?yàn)槲覀儗幵甘謩?dòng)創(chuàng)建模塊的所有結(jié)構(gòu)。
Odoo addon模塊是一個(gè)包含 manifest.py 描述文件的目錄
備注
在以前的版本中,此描述符文件命名為 openerp.py。 此名稱仍然受支持,但已被棄用
????????它還需要是 Python 可導(dǎo)入的,因此它還必須有一個(gè) init.py 文件。模塊的目錄名稱是其技術(shù)名稱。 我們將使用todo_app。 文件名稱必須是有效的Python標(biāo)識(shí)符:它應(yīng)以字母開頭,并且只能包含字母,數(shù)字和下劃線字符。
????????以下命令將創(chuàng)建模塊目錄并在其中創(chuàng)建一個(gè)空的init.py文件,?/ odoo-dev / customaddons / todo_app / __ init__.py 如果想通過命令行,下面的命令行你將會(huì)用到:
$ mkdir ~/odoo-dev/custom-addons/todo_app
$ touch ~/odoo-dev/custom-addons/todo_app/__init__.py
????????接下來,我們需要?jiǎng)?chuàng)建清單文件。 它只包含一個(gè)Python字典,里面大約有十幾個(gè)可能的屬性; 其中,只有 name 屬性是必填的。描述屬性(對(duì)于較長(zhǎng)的描述)和作者屬性是建議填寫的。 我們現(xiàn)在應(yīng)該在init.py文件旁邊添加一個(gè)manifest.py文件,其中包含以下內(nèi)容
{
'name': 'To-Do Application',
'description': 'Manage your personal To-Do tasks.',
'author': 'Daniel Reis',
'depends': ['base'],
'application': True,
}
????????depends 屬性可以包含所依賴的其他模塊的列表。 當(dāng)安裝此模塊時(shí),Odoo 將自動(dòng)安裝它們。 這不是一個(gè)強(qiáng)制性的屬性,但建議總是包含它。 如果不需要特定的依賴,我們應(yīng)該依賴于核心 base 模塊。你應(yīng)該注意確保所有依賴關(guān)系在這里明確設(shè)置; 如果其所依賴的模塊在其之后加載,模塊可能無法安裝在干凈的數(shù)據(jù)庫(kù)(由于缺少依賴關(guān)系)或有加載錯(cuò)誤。
????????對(duì)于我們的應(yīng)用程序,我們不需要任何特定的依賴關(guān)系,因此我們僅依賴于 base 模塊 為了簡(jiǎn)明起見,我們選擇使用非常少的描述鍵,但是在真實(shí)的情況下,我們建議您還使用附加鍵,因?yàn)樗鼈兣c Odoo 應(yīng)用商店相關(guān):
summary 顯示為模塊的副標(biāo)題
version 默認(rèn)為 1.0。 它應(yīng)該遵循版本語(yǔ)義規(guī)則(詳見http://semver.org/)
license 許可證標(biāo)識(shí)符,默認(rèn)為L(zhǎng)GPL-3
website 網(wǎng)站是一個(gè)用于查找有關(guān)模塊的更多信息的URL。 這可以幫助人們找到更多的文檔或問題跟蹤,以提出 Bug 和建議。
category是模塊的功能類別,默認(rèn)為Uncategorized。 現(xiàn)有類別的列表可以在【應(yīng)用程序】下拉列表中的安全組表單(設(shè)置|用戶|組)中找到其它可用的描述符:
installable 默認(rèn)為 True,但可以設(shè)置為 False 以禁用模塊
auto_install 如果設(shè)置為True,此模塊將被自動(dòng)安裝,前提是其所有依賴項(xiàng)都已安裝。 它用于必裝模塊
????????從Odoo 8.0 開始,我們可以在模塊的頂層目錄中使用 README.rst 或 README.md 文件替代描述鍵。
2.1.4.關(guān)于許可證
????????為您的工作選擇許可證非常重要,您應(yīng)該仔細(xì)考慮您最佳的選擇及其影響。 Odoo模塊使用最多的許可證是GNU通用公共許可證(LGLP)和Affero通用公共許可證(AGPL)。 LGPL更為寬容,允許商業(yè)衍生工作,而不需要共享相應(yīng)的源代碼。 AGPL是一個(gè)更強(qiáng)大的開源許可證,需要派生工作和服務(wù)托管來共享其源代碼。 請(qǐng)?jiān)L問https://www.gnu.org/licenses/了解有關(guān)GNU許可證的更多信息。
2.1.5.添加 addons 路徑
????????現(xiàn)在我們有一個(gè)簡(jiǎn)單的新模塊,我們希望將它提供給 Odoo 實(shí)例。 為此,我們需要確保包含該模塊的目錄位于addons路徑中,然后更新Odoo模塊列表。 在上一章中已經(jīng)詳細(xì)解釋了這兩個(gè)動(dòng)作,但是在這里,我們將繼續(xù)簡(jiǎn)要介紹一下需要的內(nèi)容。 我們將在我們的工作目錄中定位并使用適當(dāng)?shù)腶ddons路徑配置啟動(dòng)服務(wù)器:
$ cd ~/odoo-dev
$ ./odoo/odoo-bin -d todo --addons-path ="custom-addons, odoo/addons" --save
????????--save選項(xiàng)保存您在配置文件中使用的選項(xiàng)。這使我們?cè)谥匦聠?dòng)服務(wù)器時(shí)重復(fù)使用它們:只需運(yùn)行./odoobin,并使用上次保存的選項(xiàng)。 仔細(xì)查看服務(wù)器日志。應(yīng)該有一個(gè)INFO? odoo:addons paths:[...] line。它應(yīng)該包括我們的 custom-addons 目錄。 記住還要包括您可能正在使用的任何其他插件目錄。例如,如果您還有一個(gè) ~/odoo-dev/extra 目錄,其中包含要使用的其他模塊,則可能還要使用--addons-path選項(xiàng)來包含它們:
--addons-path =“custom-addons, extra, odoo/addons”
????????現(xiàn)在我們需要Odoo實(shí)例來識(shí)別剛添加的新模塊。
2.1.6.安裝新模塊
????????在“應(yīng)用程序”頂部菜單中,選擇“更新應(yīng)用程序列表”選項(xiàng)。這將更新模塊列表,添加自上次更新以來可能添加到列表中的任何模塊。請(qǐng)記住,我們需要啟用開發(fā)人員模式才能看到。
注意
確保您的Web客戶端會(huì)話正在使用正確的數(shù)據(jù)庫(kù)。您可以在右上角查看:數(shù)據(jù)庫(kù)名稱顯示在括號(hào)中,緊隨用戶名。強(qiáng)制使用正確數(shù)據(jù)庫(kù)的方法是使用附加選項(xiàng)
--db-filter = ^MYDB$
啟動(dòng)服務(wù)器實(shí)例。
????????應(yīng)用程序選項(xiàng)向我們顯示可用模塊的列表。默認(rèn)情況下,它只顯示應(yīng)用程序模塊。由于我們創(chuàng)建了一個(gè)應(yīng)用程序模塊,因此我們不需要?jiǎng)h除該過濾器來查看它。在搜索中鍵入todo,您應(yīng)該看到我們的新模塊。
2.1.7.升級(jí)模塊
????????開發(fā)一個(gè)模塊是一個(gè)迭代的過程,它會(huì)把你在源代碼中更改的功能,在 Odoo 中體現(xiàn)出來。在大多數(shù)情況下,只需要升級(jí)你的模塊:在應(yīng)用程序列表中的模塊,一旦它已經(jīng)安裝,你就可以使用升級(jí)按鈕。然而,如果只修改了 Python 代碼,升級(jí)就可能沒有效果。除了模塊的升級(jí),還需要重新啟動(dòng)應(yīng)用程序服務(wù)器。只要 Odoo 成功加載了 Python 代碼,以后任何代碼的更改都需要重新啟動(dòng)服務(wù)器才能應(yīng)用。
????????在某些情況下,如果模塊更改了數(shù)據(jù)文件和 Python 代碼,您可能需要同時(shí)做這兩種操作。對(duì)于Odoo新開發(fā)人員來說,這是很容易混淆。但幸運(yùn)的是,還有更好的方式。更改我們的模塊最安全和最快的方式,是停止并重新啟動(dòng)服務(wù)器,并按要求把我們的模塊升級(jí)到我們工作的數(shù)據(jù)庫(kù)。在終端服務(wù)器實(shí)例運(yùn)行時(shí),使用ctrl 鍵 + C 來停止它。然后,啟動(dòng)服務(wù)器和升級(jí) todo_app 模塊,使用下面的命令︰
python odoo-bin -c /etc/odoo10-server.conf --stop-after-init -d xxxx -u all
$./odoo-bin -d todo -u todo_app
????????-u 選項(xiàng)(或 —— update) 需要 -d 選項(xiàng),并需要一個(gè)逗號(hào)分隔更新的模塊列表。例如,我們可以使用 -u todo_app,mail。一個(gè)模塊更新時(shí),也將更新所有其他依賴它的已安裝的模塊。 -all 是更新所有模塊。
????????這是必須保持的繼承機(jī)制,用于擴(kuò)展功能的完整性。
????????總體來說,當(dāng)你需要更新應(yīng)用模塊時(shí),最安全的方法是利用前面講述的命令重新啟動(dòng) Odoo 實(shí)例。按 up 鍵就可以使用前面的命令。所以,大多數(shù)情況下,你會(huì)發(fā)現(xiàn)自己經(jīng)常使用 Ctrl + C ,up 和 Enter 鍵組合。
????????值得特別注意的是,更新模塊列表和卸載模塊這兩種操作,都不可以通過命令行操作。需要在 web 界面的應(yīng)用程序菜單中進(jìn)行。
2.1.8.服務(wù)器開發(fā)模式
????????Odoo 10 新的選項(xiàng)特性,更方便開發(fā)者進(jìn)行開發(fā)。要使用它,在啟動(dòng)服務(wù)器實(shí)例時(shí),附加選項(xiàng)--dev=all。這有幾個(gè)小技巧,可以縮短我們的開發(fā)周期。最重要的是︰
????????一旦保存Python文件,自動(dòng)重新加載 Python 代碼,避免手動(dòng)重啟服務(wù)器;從 XML 文件中,直接獲取視圖定義,避免手動(dòng)模塊升級(jí);
????????--dev選項(xiàng)接受一個(gè)逗號(hào)分隔的列表,然而大部分時(shí)間都使用的是合適的all選項(xiàng)。我們還可以指定使用的調(diào)試器。默認(rèn)情況下,Python 調(diào)試器,使用pdb 。有些人可能喜歡安裝和使用其他調(diào)試程序。它也支持ipdb和 pudb調(diào)試。
2.2.模型層
????????讓我們開始在Odoo中添加一個(gè)簡(jiǎn)單的新模型。
????????模型描述業(yè)務(wù)對(duì)象,例如商機(jī)、銷售訂單或合作伙伴(客戶,供應(yīng)商等)。 模型具有屬性列表,并且還可以定義特定的業(yè)務(wù)邏輯。
????????模型是從 Odoo 模板類派生的 Python 類實(shí)現(xiàn)的。 它們直接轉(zhuǎn)換為數(shù)據(jù)庫(kù)對(duì)象,Odoo在安裝或升級(jí)模塊時(shí)會(huì)自動(dòng)處理。負(fù)責(zé)此機(jī)制的是對(duì)象關(guān)系模型(ORM)。
????????我們的模塊將是一個(gè)非常簡(jiǎn)單,記錄保留待辦事項(xiàng)的應(yīng)用程序。
????????應(yīng)用程序的主要功能有:用于描述的簡(jiǎn)單文本字段、用于將其標(biāo)記為完成的復(fù)選框、最后需要添加一個(gè)按鈕來清除已完成任務(wù)的舊的待辦事項(xiàng)列表。
2.2.1.創(chuàng)建數(shù)據(jù)模型
????????Odoo 開發(fā)指導(dǎo)指出,模型的 Python 文件應(yīng)放在一個(gè) models 子目錄中。為了簡(jiǎn)單起見,我們先不遵循這一準(zhǔn)則,我們?cè)?todo_app 模塊的主目錄中創(chuàng)建一個(gè)todo_model.py文件。在文件中添加以下內(nèi)容:
# -*- coding: utf-8 -*-
from odoo import models, fields
class TodoTask(models.Model):
_name = 'todo.task'
_description = 'To-do Task'
name = fields.Char('Description', required=True)
is_done = fields.Boolean('Done?')
active = fields.Boolean('Active?', default=True)
????????第一行是一個(gè)特殊的標(biāo)記告訴Python解釋器,這個(gè)文件有UTF-8,以便它可以期望和處理非ASCII字符。我們不會(huì)使用任何非 ANSI 字符,但無論如何這是一個(gè)很好的做法。
????????第二行是Python代碼import語(yǔ)句,從Odoo核心導(dǎo)入模型和字段對(duì)象。
????????第三行聲明了我們的新模型。它是從models.Model派生的類。
????????第四行設(shè)置_name屬性,定義將在整個(gè)Odoo中引用此模型的標(biāo)識(shí)符。注意,實(shí)際的Python類名,在這個(gè)例子中,TodoTask對(duì)其他Odoo模塊是無意義的。 _name值將用作標(biāo)識(shí)符。
????????請(qǐng)注意,此行和以下行是縮進(jìn)的。如果你不熟悉Python,你必須知道這是很重要的:縮進(jìn)定義一個(gè)嵌套的代碼塊,所以這四行應(yīng)該是同樣縮進(jìn)。
????????然后我們有_description模型屬性。它不是強(qiáng)制性的,但它為模型記錄提供了一個(gè)用戶友好的名稱,可用于用戶友好的消息。
????????最后三行定義模型的字段。值得注意的是name和active是特殊的字段名。默認(rèn)情況下,當(dāng)從其他模型引用它時(shí),Odoo將使用name字段作為記錄的標(biāo)題。active字段用于停用記錄,默認(rèn)情況下,僅顯示活動(dòng)記錄。我們將使用它來清除已完成的任務(wù),而不會(huì)從數(shù)據(jù)庫(kù)中刪除它們。
????????現(xiàn)在,該文件尚未被模塊使用。我們必須告訴Python使用init.py文件中的模塊加載它。讓我們編輯它以添加以下行:
from . import todo_model
????????就是這樣而已!為了使我們的Python代碼更改生效,服務(wù)器實(shí)例需要重新啟動(dòng)(除非它使用--dev模式)。
????????我們不會(huì)看到任何菜單選項(xiàng)來訪問這個(gè)新模型,因?yàn)槲覀冞€沒有添加它們。我們?nèi)匀豢梢允褂眉夹g(shù)菜單查看新創(chuàng)建的模型。在頂部菜單設(shè)置中,轉(zhuǎn)到技術(shù)|數(shù)據(jù)庫(kù)結(jié)構(gòu)|模型,在列表中搜索todo.task模型,并單擊它以查看其定義:

????????如果一切正常,則確認(rèn)已創(chuàng)建模型和字段。如果您在此處看不到它們,請(qǐng)嘗試重新啟動(dòng)服務(wù)器并進(jìn)行模塊升級(jí),如前所述。
????????我們還可以看到一些我們沒有聲明的額外字段。這些是Odoo自動(dòng)添加到每個(gè)新模型的保留字段。它們?nèi)缦滤荆?/p>
- id是模型中每個(gè)記錄的唯一數(shù)字標(biāo)識(shí)符。
- create_date和create_uid指定創(chuàng)建記錄的時(shí)間和由誰(shuí)創(chuàng)建它。
- write_date和write_uid確認(rèn)記錄的上次修改時(shí)間以及誰(shuí)對(duì)其進(jìn)行了修改。
- __last_update是一個(gè)實(shí)際上不存儲(chǔ)在數(shù)據(jù)庫(kù)中的幫助信息。它用于并發(fā)檢查。
2.2.2.加入自動(dòng)化測(cè)試
????????最佳編程實(shí)踐包括自動(dòng)測(cè)試你的代碼。 這對(duì)動(dòng)態(tài)語(yǔ)言更為重要,如 Python語(yǔ)言。 因?yàn)闆]有編譯的步驟, 代碼實(shí)際是解釋運(yùn)行的,所以無法確定有無語(yǔ)法錯(cuò)誤的。 一個(gè)優(yōu)秀的編輯器可以提前幫助我們發(fā)現(xiàn)這些問題, 但卻不能幫助我們確保代碼按照預(yù)期的執(zhí)行,比如自動(dòng)化測(cè)試。
????????Odoo支持使用兩種方式來描述測(cè)試: 使用 YAML 數(shù)據(jù)文件或使用 Python 代碼、基于 Unittest2 庫(kù)。 YAML 測(cè)試是一種遺留下來的舊老版本, 不建議使用。 我們會(huì)更樂意使用 Python 測(cè)試并將添加基本的測(cè)試實(shí)例到我門的模塊。
????????測(cè)試代碼文件必須用test_開頭 , 并且從tests/init.py文件導(dǎo)入。 但 測(cè)試的 目錄(或 Python 的子模塊)不應(yīng)從模塊的頂部的init.py導(dǎo)入, 因?yàn)閮H在測(cè)試的執(zhí)行的時(shí)候會(huì)自動(dòng)被發(fā)現(xiàn)并裝載。
????????測(cè)試必須放置在 tests/的 子目錄中。 添加一個(gè)tests/init.py 文件,包含如下內(nèi)容:
from . import test_todo
????????現(xiàn)在添加實(shí)際的測(cè)試代碼放在tests/test_todo.py文件里:
# -*- coding: utf-8 -*-
from odoo.tests.common import TransactionCase
class TestTodo(TransactionCase):
def test_create(self):
"Create a simple Todo"
Todo = self.env['todo.task']
task = Todo.create({'name': 'Test Task'})
self.assertEqual(task.is_done, False)
????????這里增加了一種簡(jiǎn)單的測(cè)試?yán)觼韯?chuàng)建新的to-do任務(wù)來驗(yàn)證測(cè)試?yán)邮欠癖粓?zhí)行? 測(cè)試?yán)拥淖侄尉哂泻线m的默認(rèn)值。
????????現(xiàn)在我們即將運(yùn)行我們的測(cè)試。 當(dāng)我們?cè)诎惭b模,可以添加 --test-enable選項(xiàng)。
????????該Odoo服務(wù)器將尋找一個(gè)tests/子目錄的升級(jí)模塊 并運(yùn)行。如果有任何測(cè)試失敗了,服務(wù)器日志都會(huì)在這里顯示。