大家好鴨,我又來更新啦!還記得我們在第二篇教程中提到過的動作(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」中,如果遇到什麼問題,歡迎提出,我會及時解答 ;-)