「Odoo 基礎教程系列」第六篇——從 Todo 應用開始(5)
大家好鴨,我又來更新啦!還記得我們在第二篇教程中提到過的動作(actions)嗎,今天我們就來專門講講在 Odoo 中的 action
,學習不同型別的動作對應的應用場景,並且在我們的 Todo 應用中使用上其中一些型別的動作。
視窗動作
視窗動作在 Odoo 中是最常見也是最常用的動作型別,在第二篇教程中我們建立選單的時候就已經用過視窗動作了,我們開啟 menus.xml
來看看一個視窗動作的組成:
<!-- menus.xml --> <record id="action_todo_task" model="ir.actions.act_window"> <field name="name">待辦事項</field> <field name="res_model">todo.task</field> <field name="view_type">form</field> <field name="view_mode">tree,form</field> <field name="target">current</field> </record>
這裡的 model
之前我們也說過,對應的是這個動作的型別(每個型別的動作都對應一個模型),我們重點來看看下面列出的欄位以及沒有列出來的欄位,分別說明一下它們各自的作用。
-
res_model
:要開啟的檢視(視窗)關聯的資料模型 -
view_type
:檢視型別,預設值為form
,一般情況下我們取預設值就可以了 -
view_mode
:允許開啟的檢視型別,以逗號分隔,預設值為tree,form
-
target
:開啟的視窗型別,常用的有current
(當前視窗開啟)和new
(彈窗開啟)這兩種,預設為current
除了上述列出的一些欄位外,還有一些非必填的欄位在某些時候我們是會用上的,這裡也分列出來:
-
view_ids
:關聯的檢視物件 id,需注意區分和view_id
的區別 -
view_id
:關聯的檢視的 id, 例如在不同時候需要開啟同一個資料模型不同的表單檢視,就可以通過這個欄位指定要開啟的檢視的 id -
res_id
:僅在檢視型別為form
時有效,表示開啟該 id 對應的記錄的表單檢視,如未指定則開啟新建頁面 -
context
:傳遞到上下文中的資料,一個字典 -
domain
:過濾規則,對檢視中的記錄進行過濾 -
limit
:列表中每頁顯示的記錄數量,預設為 80 -
search_view_id
:指定搜尋檢視,不指定則按預設規則載入 -
multi
:如果設定為True
且動作綁定了模型(src_model
-
views
:由(view_id, view_type)
這樣的元組對組成的列表,view_id
為指定檢視的 id 或是False
(按預設值取出對應檢視),view_type
表示檢視型別
其中 views
是一個計算欄位,該欄位會根據 view_ids
, view_mode
和 view_id
自動計算出來,大致分為三個步驟:
- 從
view_ids
中順序取出 id 和檢視型別,組成(view_id, view_type)
元組對加入到views
列表中 - 若定義了
view_id
且對應的檢視型別不在view_ids
中,則加入到views
中 - 最後對
view_mode
中指定的檢視型別,但是不存在於view_ids
和view_id
中,則將其view_id
置為False
組成元組對後加入到views
中
這裡需要強調一點的是,如果我們在某些時候需要直接通過 Python 程式碼或 JS 程式碼開啟一個視窗動作,此時我們將需要自己新增 views
欄位,否則將會丟擲錯誤,具體的例項我們將在之後使用到了再進行講解分析。
伺服器動作
Server Action 可以在服務端執行復雜的邏輯程式碼,是非常強大的一種動作型別。我們先給代辦事項新增一個 Server Action 用於快速完成任務的動作,這樣我們就不用每次都要點進去一個任務然後進入編輯狀態再勾選儲存這麼多步驟了。
我們來看看定義一個最簡單的 Server Action 應該包含哪些內容:
<!-- views.xml -->
<record id="action_mark_todo_task_done" model="ir.actions.server">
<field name="name">標記完成</field>
<field name="model_id" ref="model_todo_task"/>
<field name="binding_model_id" ref="model_todo_task"/>
<field name="state">code</field>
<field name="code">records.write({'is_done': True})</field>
</record>
和其他所有在資料檔案(XML)中定義的資料一樣,首先是一個包含屬性 id
和 model
的 <record />
標籤,我們要定義的是 Server Action, 所以需要將 model
設定為 ir.actions.server
,然後是對應 Server Action 模型下的一些欄位:
-
model_id
:當前的動作是在哪個模型上執行的 -
binding_model_id
:繫結的模型,當前動作將會出現在繫結的模型的檢視中 -
state
:伺服器動作的型別,總共有 4 種可選的型別,分別是code
(執行 Python 程式碼),object_create
(建立一條新記錄),object_write
(更新記錄),multi
(執行多個動作) -
code
:對應state
的型別code
,為當前動作執行時所要執行的 Python 程式碼
大家應該都留意到了在上面的定義中出現了一個屬性 ref
,如果我沒有理解錯,它應該是 reference
的縮寫,它的值是一個外部 ID(external id
),我們上面定義的這個動作的外部 ID 就是定義時新增的 id
屬性的值 action_mark_todo_task_done
,它指向一條具體的記錄(就像 Many2one
欄位一樣)。
我們定義的所有模型都會在 ir.model.data
對應的表中存在相應的記錄,這些模型的外部 ID 形如 model_model_name
,其中 model_name
是將模型名 [model.name](http://model.name)
的 .
替換成 _
,例如我們的 todo.task
模型的外部 ID 就是字首 model_
加上 todo_task
組成的 model_todo_task
了。
接下來我們再看到欄位 code
裡面的內容,在這裡面我們有一些變數是可以直接使用的:
-
env
:Odoo 的執行環境 -
model
:動作觸發時對應的 Odoo 模型例項 -
record
:動作觸發時對應的單個記錄(如在表單檢視中執行對應當前表單所指向的記錄),可能是空的 -
records
:動作觸發時對應的記錄集(如在列表檢視中勾選多條記錄觸發,記錄集指向這些選中的記錄),可能是空的 - Python 庫:
time
,datetime
,dateutil
,timezone
時間相關的 Python 庫 -
log
:用來記錄日誌資訊 -
Warning
:通過raise Warning('xxxxx')
丟擲警告資訊
除了上述可以直接使用的變數外,還有一個 action
變數,當我們想讓當前動作執行完畢之後,返回一個新的動作繼續執行,就可以將返回的動作的定義(一個字典)賦值給變數 action
,客戶端將會自動執行該動作。
OK, 前面說了這麼多,我們更新一下程式碼,然後重新整理瀏覽器看看效果吧:
在列表檢視中,當我們勾選了任意的記錄後,將會出現一個「動作」選單,開啟之後就可以看到我們剛剛定義的「標記完成」這個 Server Action 了,試試看執行會發生什麼,注意觀察「已完成?」這一列的變化。然後再建立一條新的記錄,在表單頁面中,同樣有「動作」選單,我們在這裡也可以執行「標記完成」的動作,怎麼樣,是不是比原本的編輯再勾選再儲存要方便得多了,而且我們還能在列表裡勾選多條記錄進行批量操作,不能更方便了!
受限於篇幅,我們這裡只涉及了 state
為 code
型別的伺服器動作,相對其他三種類型,已經足以應付絕大多數場景的需求了,這裡就不展開細說,感興趣的同學可以看看官方模組的相關實現,要學會看原始碼哈!
URL 動作
URL Action 用來開啟一個網頁連結,十分簡單的一種動作型別:
<record id="action_open_google" model="ir.actions.act_url">
<field name="name">開啟谷歌</field>
<field name="target">new</field>
<field name="url">https://google.com</field>
</record>
上面這個動作觸發後將會新開瀏覽器視窗(或新標籤)開啟谷歌首頁,主要的兩個欄位如下:
-
target
:有兩個可選值,分別是新視窗(new
)開啟連結,相當於<a target='_blank' />
,以及當前視窗(self
)開啟,相當於<a target='_self' />
-
url
:要開啟的目標頁面的連結,可以是外部頁面也可以是同域下的內部頁面
客戶端動作
觸發一個完全由客戶端(瀏覽器)執行的動作,例如某些模組的「儀表板」就屬於 Client Action,它的基本組成如下:
<record id="backend_dashboard" model="ir.actions.client">
<field name="name">Dashboard</field>
<field name="tag">backend_dashboard</field>
</record>
上面這個 Client Action 是在 Odoo 自帶模組 website
中定義,用來開啟儀表板,來看看客戶端動作有哪些欄位是可用的:
-
tag
:客戶端動作的標識,需要是在action_registry
中註冊了的動作 -
target
:同窗口動作 -
context
:同窗口動作 -
params
:傳遞給客戶端動作的引數,一個字典
客戶端動作的本體實際上是 tag
所指向的動作,這個動作是用 JS 編寫的一些邏輯(在 Odoo 的 JS 框架下),在之後會有專門的教程教大家相關的內容,這裡請先略過。
報表動作
這型別的動作用於觸發報表列印,例如打印發票等。這裡不對該型別作介紹,感興趣的同學同樣可以去看看 Odoo 自帶的一些模組如 account
等。
瞎說幾句
在實際開發中,最常接觸和使用的動作基本上就視窗動作(ir.actions.act_window
)和伺服器動作(ir.actions.server
)這兩種了,其中 Server Action 最複雜也最強大,可以用它來實現很多的功能。
上面沒有展開細說的內容,希望大家可以多多翻看官方模組的實現,學會閱讀原始碼才是最好的學習方式。
教程中的程式碼會更新在 GitHub 倉庫「Odoo-Tutorial-Demo」中,如果遇到什麼問題,歡迎提出,我會及時解答 ;-)