odoo模塊包括 業務對象,web控制器,數據文件,前面2個是Python模塊,而數據文件則是odoo特有的文件,例如,odoo數據文件,web數據。這些數據文件在 __odoo__.py 進行定義,在 odoo10之前,這個 manifest 文件命名為 __openerp__.py,在更早的 tinyERP時代,名為 __terp__.py
? ?
manifest 包含以下項目
'application' | 是否作為應用程序列出,默認 False, |
'author' | 默認 'Odoo SA', |
'auto_install' | 默認 False, |
'bootstrap' | ?? |
'category' | 默認 'Uncategorized', |
'data' | 數據文件,例如基礎數據,視圖,動作,菜單,報表 |
'demo' | 演示數據 |
'depends' | 默認 [], |
'description' | 默認為空 |
'icon' | 模塊的圖標,默認讀取 static/description/icon.png,如果沒有指定,則使用默認圖標 |
'installable' | 默認 True, |
'license' | 默認 'LGPL-3', |
'post_load' | 默認 None, |
'qweb' | web client使用的模板 |
'version' | 默認 '1.0', |
'web' | 默認 False, |
'website' | |
'sequence' | 默認 100, |
'summary' | 默認為空 |
?? | ?? |
?? | ?? |
模塊的處理過程
- odoo模塊的業務對象部分和Web控制器部分,都是Python模塊在odoo啟動時動態構建為odoo modelclass并實例化,成為最終的業務對象
- odoo數據文件則在安裝模塊的時候,解析為業務對象的記錄,并寫入到 數據庫
- web數據在客戶端訪問時,被打包為 /web/webclient/csslist、 /web/webclient/jslist 、 /web/webclient/qweb 等,供運行在瀏覽器的webclient使用
? ?
模塊發現
當在odoo啟動裝載base模塊之后,會調用 ir.module.module 模型的 方法 update_list 對 addons_path 中指定的 模塊進行 發現, 對于發現的模塊,更新到 ir.module.module 對應的 數據庫表, 這樣, 在 odoo backend 的 管理界面就能 查看到所有發現的模塊
? ?
模塊安裝
當 ir.module.module 的模塊標記為 installed 狀態時,在odoo啟動時,會嘗試進行安裝
或者 在 apps 安裝界面 點擊 安裝 按鈕進行安裝
? ?
點擊模塊的安裝按鈕時, 執行 openerp\addons\base\module\module.py#button_immediate_install() 方法,先對需要安裝的模塊進行一次驗證和標記, 進而重建一次注冊表,從而觸發 odoo modelclass 重建過程,以及模塊數據裝載過程
? ?
所以,模塊安裝對系統的消耗很大。
? ?
? ?
模塊數據裝載
當在odoo啟動時指定 init 或者 update 指令時、或者有新的模塊需要安裝時,在 ORM 完成之后,調用 openerp\modules\loading.py#_load_data() 裝載 模塊里面定義的 數據。 而 _load_data() 再調用 openerp\tools\convert.py#convert_file() 從模塊讀取 manifest 里面 data 以及 demo 指定的 數據文件
? ?
數據文件的目的是往模型里面寫入數據,支持的格式
- csv
- xml
- sql
- yml
? ?
CSV
csv 文件名本身 指定了 model 的名稱,csv 文件以 model.csv 的格式命名,model 就是該模型; csv 文件內容的第一行,是數據的欄位名,其他行則是 數據,對于關系數據, 使用 external_id 的形式進行引用, 例如
1 文件名 代表了 該數據對應的模型,此例是 ir.model.access
2 第一行,代表了 數據對于的模型欄位
? ?
XML
xml 文件 包含多個 <data> 標簽, data標簽的屬性 noupdate 用來 指明 該標簽包含的 記錄是否是'可更新',意思是在更新/升級該模塊的時候,是否更新該記錄在數據庫中的數據記錄
? ?
<data>標簽可以包含多個<record>標簽,表明這是一數據記錄, record 標簽 的 model屬性 指定了 model的名稱,id 屬性 指定該 記錄的 external_id,
<record>標簽可以包含多個<field> 標簽 ,表示是 模型的字段,字段的名稱使用 field 的屬性 name 來表示
? ?
例如
? ?
<record id="res_partner_title_madam" model="res.partner.title">
<field name="name">Madam</field>
<field name="shortcut">Mrs.</field>
</record>
表示的是 模型 "res.partner.title" 的一條記錄, 字段名 和 值 分別是 field標簽表示的
? ?
<record id="view_partner_title_tree" model="ir.ui.view">
<field name="name">res.partner.title.tree</field>
<field name="model">res.partner.title</field>
<field name="arch" type="xml">
<tree string="Partner Titles">
<field name="name"/>
<field name="shortcut"/>
</tree>
</field>
</record>
表示的是 模型 "ir.ui.view" 的一條記錄, 字段名 和 值 分別是 field標簽表示的。說明,視圖定義是 arch 字段,它的類型是 xml,這樣 在 安裝模塊數據的時候,將這部分轉換為 XML
? ?
? ?
? ?
XML數據文件除了 record標簽之外,還支持
- template,數據記錄,為ir.ui.view 的別名
- report,數據記錄,為ir.actions.report.xml別名
- menuitem,數據記錄,為ir.ui.menu別名
- workflow, 向工作流觸發一個信號
- act_window
- function
- delete,刪除記錄
- ir_set
- assert
? ?
? ?
template
qweb template,它是 ir.ui.view 的別名,例如 web公用的 bootstrap 資源 別定義在 template 標簽里面
當渲染這個模板的時候,將會把template 里面定義的 頁面片段插入到 前臺html中
? ?
template裝入后,作為ir.ui.view 模型的 arch 字段 保存在數據庫
? ?
? ?
Web數據
web數據分2部分,一個在后端渲染,qweb template 用來描述 web page的組成;另外一個是前端渲染, qweb template 用來描述 web client widget 的組成。
? ?
page qweb template
例如, 在訪客訪問 / 時, 被重定向到 /web/login 后端調用 qweb 引擎ir_qweb.py 將 模板 web.login 進行渲染,
? ?
將渲染的結果返回給 瀏覽器
? ?
返回里面 包含了 前端【在此指網頁】以及公共的 樣式和 JS資源 的鏈接
?
這幾個 資源在 模板 login_layout 中進行了定義
? ?
? ?
? ?
? ?
web client qweb template
? ?
一旦登錄成功,重定向到 /web ,并給瀏覽器 返回 'web.webclient_bootstrap' 模板 的渲染結果, 啟動webclient
? ?
'web.webclient_bootstrap' 模板 描述了 /web 頁面的組件
? ?
odoo Web control在 使用 Qweb引擎渲染 它的時候, 將 模板 web.assets_common 打包為 assets. 也就是 http://127.0.0.1:8069/web/content/1012-751b3f4/web.assets_common.js
對于其他的 qweb 元素,進行類似的 打包工作
? ?
webclient 的啟動入口
? ?
? ?
? ?
web client啟動時,還會從后端 通過 /web/webclient/qweb 取得 當前數據庫所安裝模塊的 前端 qweb Template ,對于還沒登陸的 數據庫,此時是 空白。
根據前端請求送入的mods 參數,遍歷 qweb 定義的 XML文件,然后把他們 打包在一起
? ?
例如其中 FieldChar 的定義如下
? ?
在 Webclient 渲染具有 Char 字段時, 就 會 調用 Qweb.render_element() 進行渲染
? ?
odoo模塊
技術