Odoo 起初是一個后台系統,但很快就有了前端界面的需求。早期基於后台界面的門戶界面不夠靈活並且對移動端不友好。為解決這一問題,Odoo 引入了新的網站功能,為系統添加了 CMS(Content Management System)內容管理系統。這使得我們無需集成第三方 CMS 便可創建美觀又高效的前端。本文中我們將學習如何利用 Odoo 自帶的網站功能開發面向前端的插件模塊。
本文主要內容有:
- 學習項目 – 自助圖書館
- 第一個網頁
- 創建網站
開發准備
我將用第十一章 Odoo 12開發之看板視圖和用戶端 QWeb中最后編輯的library_checkout插件模塊,代碼請見GitHub 倉庫。本文完成后的代碼也請參見GitHub 倉庫。
學習項目 – 自助圖書館
本文中我們將為圖書會員添加一個自助服務功能。可供會員分別登錄賬號來訪問他們的借閱請求列表。這樣我們就可以學習網站開發的基本技術:創建動態頁面、在頁面間傳遞參數、創建表單以及處理表單數據驗證。對這些新的圖書網站功能,我們要新建一個插件模塊library_website。
大家應該已經輕車熟路了,首先創建插件的聲明文件ibrary_website/__manifest__.py,代碼如下:
網站功能將會依賴於library_checkout。我們並沒有添加對website核心插件模塊的依賴。website插件為創建完整功能的網站提供了有用的框架,但現在我們僅探討核心框架自帶的基礎網站功能,尚無需使用website。我們想要圖書會員通過登錄信息在圖書網站上訪問自己的借閱請求。為此需要在圖書會員模型中添加一個user_id字段,需要分別在模型和視圖中添加,下面就開始進行網站的創建:
1、添加library_website/models/library_member.py文件
2、添加library_website/models/__init__.py文件:
3、添加library_website/__init__.py文件:
4、添加library_website/views/library_member.xml文件:
訪問這些網頁的都是門戶用戶,無需訪問后台菜單。我們需要為這個用戶組設置安全訪問權限,否則會在使用圖書網站功能時報權限錯誤。
5、添加library_website/security/ir.model.access.csv文件,添加對圖書模型的讀權限:
6、在library_website/security/library_security.xml文件中添加記錄規則來限制門戶用戶所能訪問的記錄:
base.group_portal是門戶用戶組的標識符。在創建門戶用戶時,應設置他們的用戶類型為 Portal,而不是Internal User。這會讓他們屬於門戶用戶組並繼承我們上面定義的訪問權限:
補充:以上內容需開啟開發者模式才可見
一旦為圖書會員創建了一個門戶用戶,就應在我們會員表單中的用戶字段中使用。該登錄信息將可以訪問相應會員的借閱請求。
小貼士:在模型中使用 ACL 和記錄規則來實現安全權限比使用控制器的邏輯要更為安全。這是因為攻擊者有可能跳過網頁控制器直接使用RPC 來訪問模型 API 。
了解了這些,我們就可以開始實現圖書網站的功能了。但首先我們來使用簡單的Hello World網頁簡短地介紹下基本網站概念。
第一個網頁
要開始了解 Odoo 網頁開發的基礎,我們將先實現一個Hello World網頁來展示基本概念和技術。很有想象空間,是不是?
要創建第一個網頁,我們需要一個控制器對象。首先來添加controllers/hello.py文件:
1、在library_website/__init__.py文件中添加如下行:
2、在library_website/controllers/__init__.py文件中添加如下行:
3、添加實際的控制器文件 library_website/controllers/hello.py,代碼如下:
odoo.http模塊提供 Odoo 網頁相關的功能。我們用於渲染頁面的控制器,應該是一個繼承了odoo.http.Controller類的對象。實際使用的名稱並不是太重要,這里選擇了 Hello(),一個常用的選擇是 Main()。
在控制器類中使用了匹配 URL 路由的方法。這些路由用於做一些處理並返回結果,通常是返回用戶網頁瀏覽器的 HTML 頁面。odoo.http.route裝飾器用於為 URL 路由綁定方法,本例中使用的是/helloworld 路由。
安裝library_website模塊(~/odoo-dev/odoo/odoo-bin -d dev12 -i library_website)就可以在瀏覽器中打開http://xxx:8069/helloworld,我們應該就可以看到Hello World問候語了。
本例中方法執行的處理非常簡單,它返回一個帶有 HTML 標記的文本字符串,Hello World。
ℹ️使用這里的簡單 URL 訪問按制器,如果同一 Odoo 實例有多個數據庫時,在沒有指定目標數據庫的情況下將會失敗。這可通過在啟動配置中設置-d或–db-filter來解決,參見第二章 Odoo 12開發之開發環境准備。
你可能注意到在路由裝飾中使用了auth=’public’參數,對於無需登錄的用戶開放的頁面就需要使用它。如果刪除該參數,僅有登錄用戶方可瀏覽此頁面。如果沒有活躍會話(session)則會進入登錄頁面。
小貼士:auth=’public’參數實際表示如果訪客未登錄則使用public特殊用戶運行網頁控制器。如果登錄了,則使用登錄用戶來代替public。
使用 QWeb 模板的 Hello World
使用 Python 字符串來創建 HTML 很快就會覺得乏味。QWeb可用來增添色彩,下面就使用模板來寫一個改進版的Hello World網頁。QWeb模板通過 XML 數據文件添加,技術層面上它是與表單、列表視圖類似的一種視圖類型。它們甚至存儲在同一個技術模型ir.ui.view中。
老規矩,需要在聲明文件中添加聲明來加載文件,編輯library_website/__manifest__.py文件並添加內容如下:
然后添加實際的數據文件views/helloworld_template.xml,內容如下:
<template>實際上是一種簡寫形式,它聲明<record>將數據以type=”qweb”類型加載到ir.ui.view模型中。現在,我們需要修改控制器方法來使用這個模板:
模板的渲染是通過render()函數的 request 對象來實現的。
小貼士:注意我們添加了**kwargs方法參數。使用該參數,HTTP 請求中的任意附加參數,如GET 或 POST 請求參數,可通過 kwargs 字典捕獲。這會讓我們的方法更加健壯,因為即便添加了未預期的參數也不會產生錯誤。
HelloCMS!
下面我們來增加點趣味性,創建我們自己的簡單 CMS。為此我們可以通過 URL在路由中使用模板名(一個頁面),然后對其進行渲染。然后就可以動態創建網頁,通過我們的 CMS 來提供服務。實現方法很簡單:
以上page 參數應匹配一個模板的外部ID,如果在瀏覽器中打開http://xxx:8069/hellocms/library_website.helloworld,應該又可以看到熟悉的Hello World 頁面了。實際上內置的website模塊提供了CMS功能,在 /page路徑(endpoint)下還包含更為健壯的實現。
ℹ️在werkzeug的行話中,endpoint是路由的別名,由其靜態部分(不含占位符)來表示。比如,CMS 示例中的 endpoint為/hellocms。
大多數情況下,我們要將頁面集成到 Odoo 網站中,因此接下來的示例將使用website插件模塊。
創建網站
前面的示例並未集成到 Odoo 網站中,並有頁面 footer 和網站菜單。Odoo 的website插件模板為方便大家提供這些功能。
要使用網站功能,我們需要在工作實例中安裝website插件模塊。應當在library_website插件模塊中添加這一依賴,修改__manifest__.py的 depends 內容如下:
要使用網站功能,我們需要對控制器和 QWeb模板進行一些修改。控制器中可在路由上添加一個額外的website=True參數:
集成website模塊並非嚴格要求website=True參數,不添加它也可以在模板視圖中添加網站布局。但是通過添加可以讓我們在網頁控制器中使用一些功能:
- 路由會自動變成支持多語言並且會從網站安裝的語言中自動檢測最接近的語言。需要說明這可能會導致重新路由和重定向。
- 控制器拋出的任何異常都會由網站代碼進行處理,這會將默認的錯誤碼變成更友好的錯誤頁面向訪客展示。
- 帶有當前網站瀏覽記錄的request.website變量,可在請求中進行使用。
- auth=public路由的 public用戶將是由后台網站配置中選擇的用戶。這可能會和本地區、時區等相關。
如果在網頁控制器中無需使用上述功能,則可省略website=True參數。但大多數網站QWeb模板需要使用website=True開啟一些數據,比如底部公司信息,所以最好還是添加上。
ℹ️傳入QWeb運行上下文語言的網站數據由website/model/ir_ui_view.py文件中的_prepare_qcontext方法設定。
要在模板中添加網站的基本布局,應為QWeb/HTML包裹一個t-call=”website.layout”指令,如下所示:
t-call運行QWeb模板website.layout並向其傳遞 XML 內的tcall 節點。website.layout設計用於渲染帶有菜單、頭部和底部的完整網頁,交將傳入的內容放在對應的主區域內。這樣,我們的Hello World!示例內容就會顯示在 Odoo 網站頁面中了。
添加 CSS 和 JavaScript 資源
我們的網站頁面可能需要一些其它的 CSS 或JavaScript資源。這方面的網頁由website 管理,因此需要一個方式來告訴它使用這些文件。我們將使用 CSS 來添加一個簡單的刪除線效果,創建library_website/static/src/css/library.css文件並添加如下內容:
接下來需要在網站頁面中包含該文件。通過在website.assets_frontend模板中添加來實現,該模板用於加載網站相關的資源。添加library_website/views/website_assets.xml數據文件來繼承該模板:
很快我們就會使用text-strikeout這個新的樣式類。當然,可以使用相似的方法來添加JavaScript資源。
借閱列表控制器
既然我們已經過了一遍基礎知識,就來一起實現借閱列表吧。我們需要使用/checkout URL來顯示借閱列表的網頁。為此我們需要一個控制器方法來准備要展示的數據,以及一個QWeb模板來向用戶進行展示。
在模塊中添加library_website/controllers/main.py文件,代碼如下:
控制器獲取要使用的數據並傳給渲染的模板。本例中控制器需要一個登錄了的會話,因為路由中有一個auth=’user’屬性。這是默認行為,推薦明確指出需要用戶會話。登錄了的用戶存儲在環境對象中,通過 request.env來使用。search()語句使用它來過濾出相應的借閱記錄。
對於無需登錄即可訪問的控制器,所能讀取的數據也是非常有限的。這種情況下,我們經常需要對部分代碼采用提權上下文運行。這時我們可使用sudo()模型方法,它將權限上下文權限修改為內部超級用戶,突破大部分限制。權力越大,責任越大,我們要小心這種操作帶來的安全風險。需要特別注意在提權時輸入的參數以及執行的操作的有效性。建議將sudo() 記錄集操作控制在最小范圍內。
回到我們的代碼,它以request.render()方法收尾。和之前一樣,我們傳入了QWeb模板渲染的標識符,和模板運行用到的上下文字典。本例中我們向模板傳入 docs 變量,該變量包含要渲染借閱記錄的記錄集。
借閱 QWeb 模板
QWeb模板使用數據文件來添加,我們可以使用library_website/views/checkout_template.xml文件並添加如下代碼:
以上代碼使用t-foreach指令來迭代 docs 記錄集。我們使用了復選框 input 並在借閱完成時保持為已選狀態。在 HTML 中,復選框是否被勾選取決於是否有 checked 屬性。為此我們使用了t-att-NAME指定來根據表達式動態渲染 checked 屬性。當表達式運行結果為 None(或任意其它 false 值)時,QWeb會忽略該屬性,本例用它就非常方便了。
在渲染任務名時,t-attf指令用於動態創建打開每個指定任務的明細表單的URL。我們使用一個特殊函數slug()來為每條記錄生成易於閱讀的 URL。該鏈接目前尚無法使用,因為我們還沒有創建對應的控制器。
在每條借閱記錄上,我們還使用了t-att 指令來在借閱為最終狀態時應用text-strikeout樣式。
借閱明細頁面
借閱列表中的每一項都有一個相應明細頁面的鏈接。我們就為這些鏈接實現一個控制器,以及實現一個QWeb模板來用於展示。說到這里應該已經很明朗了。
在library_website/controllers/main.py文件中添加如下方法:
注意這里路由使用了帶有model(“library.checkout”)轉換器的占位符,會映射到方法的 doc 變量中。它從 URL 中捕獲借閱標識符,可以是簡單的 ID 數值或鏈接別名,然后轉換成相應的瀏覽記錄對象。
對於QWeb模板,應在library_website/views/checkout_template.xml數據文件中添加如下代碼:
這里值得一提的是使用了<t t-field>元素。和在后台中一樣,它處理字段值的相應展示。比如,它正確地展示日期值和many-to-one值。
補充:controllers/__init__.py和__mainfest__.py 中請自行添加控制器文件和數據文件的引用
總結
讀者現在應該對網站功能的基礎有了不錯的掌握。我們學習了如何使用網頁控制器和QWeb模板來動態渲染網頁。然后學習了如何使用website插件並使用它來創建我們自己頁面。最后,我們介紹了網站表單插件來幫助我們來創建網頁表單。這些都是創建網站功能的核心能技巧。
我們已經學習了Odoo 主要構件的開發,是時候學習如何將Odoo 服務部署到生產環境了。
☞☞☞第十四章 Odoo 12開發之部署和維護生產實例
擴展閱讀
Odoo 官方文檔中有一些對本文講解課題的補充參考材料:
- 網頁控制器
- QWeb語言
- JavaScript API指南
- Bootstrap樣式文檔
- 還可以在Packt上找到更多的 Bootstrap學習資源