參考文檔 看雲文檔參考 思否ruter文檔參考
odoo開發,需要那些工具
python
postgresql
node.js
less (css是靜態, less是動態)
git
運行odoo
1 安裝路徑: /xx/xx
2 /xx/xx/odoo-bin -c odoo-dev/odoo.conf & # odoo-dev/odoo.conf 配置文件
-c 指定配置文件文件
& 后台運行
odoo技巧
數據庫管理:http://127.0.0.1:8069/web/database/manager
數據庫選擇:http://127.0.0.1:8069/web/database/selector
數據庫指定:?db=database
后台
http://127.0.0.1:8069/web/
前台
http://127.0.0.1:8069/
登錄
http://127.0.0.1:8069/web/login
Odoo模塊組成
業務對象
Python類,這些類會被Odoo框架自動持久化,持久化的方式決定於類的定義。
數據文件
包括視圖、菜單、動作、工作流、權限、演示數據等,以XML或CSV文件定義。
Web控制器
處理Web瀏覽器的請求
靜態頁面數據
網站或界面使用的圖片、CSS或JavaScript文件
模塊結構
每個模塊都是模塊目錄中的一個子目錄, 可以通過 --addons-path 選項指定模塊目錄的路徑
odoo的設計模式 --> MVC模式
M Model
V View
C Controller
創建模塊
1 在odoo源碼同層目錄下創建目錄: mkdir myaddons
2 用odoo-bin的腳手架功能創建空的odoo模塊
./odoo-bin scaffold todo myaddons
odoo orm
參考:參考手冊
自己的筆記跳轉: odoo10 orm操作
視圖
自己的筆記跳轉: odoo10視圖
domains
通過domain來過濾數據記錄
domain作用子一個model上: 用model.search(domain)
Domain是定義模型子集的規則集合。domain表達式是由多個(field_name, operator, value)元組構成的列表或數組
field_name -- 字段名或者用.號分隔的Many2one關系的字段如:'street' , 'partner_id.country' operator(str) -- 用於對字段值和給定值進行比較的運算符: =,!=,>,>=,<,<=, =?(值為false或none時返回true,否則與=效果一致) =like()將字段數據與value進行匹配,_代表匹配單個字符、%匹配0或多個字符 like() 將字段數據與%value% 進行匹配, not like 不與%value%匹配 ilike 忽略大小寫的like函數 not ilike 忽略大小寫的not like =ilike 忽略大小寫的=like in 與value的任意值相等,value須為值列表 not in 與value的任意值都不相等 child_of 是否由value派生而來 value 對應值,必須與相應條件對應 多個domain表達式可用運算符進行連接,運算符寫在兩個表達式之前。 & 邏輯與 ,| 邏輯或,!邏輯非
1 作用在關聯字段上
示例: 當為授課選擇講師時,只有instructor值為True的講師會被顯示出來。
instructor_id = fields.Many2one('res.partner', string="Instructor", domain=[('instructor', '=', True)])
注意: 聲明為文字列表的domain會在服務端進行計算,右側不可以是動態的字段; 而聲明為字符串的domain是在客戶端進行計算的,右側可以是動態的字段
2 作用在客戶端上
當在客戶端界面選擇記錄集時,domain參數可以添加到關聯字段上,以限制只顯示有效的關聯字段。
<field name="instructor_id" domain="[('instructor', '=', True)]"/>
計算字段
odoo中提供一種每次引用字段, 通過方法動態計算的方式來獲取字段值的方法
1 創建計算字段
- 創建一個字段
- 將其屬性compute設置為(計算)方法名稱
2 計算方法
# ORM使用depends()裝飾器來指定計算方法的依賴性。當某些依賴關系被修改后,ORM層通過給定的依賴關系來觸發字段的重新計算。
@api.multi
@api.depends('value')
def _compute_name(self):
for record in self:
record.name = "Record with value %s" % record.value
默認值
字段加上屬性 default
- 可以是一個值
- 有返回值的匿名函數
對象self.env提供對請求參數和其他有用的東西的訪問
self.env.cr 或者 self._cr 是數據庫游標對象,通常用於查詢數據庫
self.env.uid或者self._uid 是當前用戶的數據庫ID
self.env.user 是當前用戶記錄
self.env.ref(xml_id) 返回XML ID對應的記錄
self.env[model_name] 返回給定模型的實例
Odoo 有內置規則:active字段值為False時記錄不可見
onchange
為客戶端接口提供了一種方法, 只要用戶填寫了字段中的值, 就可以實時更新form表單, 而無需向數據庫保存任何內容
示例
@api.onchange('amount', 'unit_price') # onchange()的參數指定了在那個字段改變時,觸發方法 def _onchange_price(self): # 業務邏輯 if flag: return { # 可以返回一個錯誤信息 'warning': { 'title': "Something bad happened", 'message': "It was very bad indeed", } }
模型約束
python代碼級別約束
在記錄集上調用這個方法。裝飾器參數指定了約束涉及的字段,當涉及的字段中任一發生改變時觸發方法執行。如果不滿足約束條件,該方法將引發異常:
示例
from odoo.exceptions import ValidationError @api.constrains('age') def _check_something(self): for record in self: if record.age > 20: raise ValidationError("Your record is too old: %s" % record.age) # all records passed the test, don't return anything
sql數據庫級別約束
SQL約束通過模型屬性_sql_constraints進行定義。
它是一個三元素的元組的列表(name, sql_definition, message)
- name 是SQL約束名稱,
- sql_definition 是約束規則,
- message 是違反約束規則時的警告信息。
示例
_sql_constraints = [ ('name_description_check', 'CHECK(name != description)', "The title of the course should not be the description"), ('name_unique', 'UNIQUE(name)', "The course title must be unique"), ]
工作流
工作流是與動態業務對象相關聯的模型。工作流也用於跟蹤動態(隨時間)演進的進程。
下面是工作流的兩種實現方式
1 偽工作流
button標簽的type='object'
給模型添加一個字段state, 用於定義一個工作流程
按鈕 --> 模型的方法
2 真工作流
button標簽的type='workflow'
與模型相關的工作流僅在創建模型記錄時被創建。因此,在工作流定義之前創建的授課實例是沒有與之對應的工作流實例的。
工作流的構成
工作流
# 有點類似一個【model的工作流模板】, 之后此model的工作流實例根據這個模板生成
xml示例代碼:
<record model="workflow" id="wkf_session"> <field name="name">OpenAcademy sessions workflow</field> <field name="osv">openacademy.session</field> <field name="on_create">True</field> </record>
活動(節點)
# 活動定義了應在Odoo服務器內完成的工作 例如更改某些記錄的狀態或發送電子郵件。
不同的調用方式:
<field name="kind">function</field> # python代碼 <field name="kind">dummy</field> # 服務器的code # 還有 Subflow 和 Stop all,可以參考官方文檔
xml示例代碼:
<record model="workflow.activity" id="draft"> <field name="name">Draft</field> <field name="wkf_id" ref="wkf_session"/> <field name="flow_start" eval="True"/> # 標示了活動的開始節點 <field name="kind">function</field> <field name="action">action_draft()</field> </record>
轉換
# 控制工作流如何從活動到活動。
xml示例代碼:
<record model="workflow.transition" id="session_draft_to_confirmed"> <field name="act_from" ref="draft"/> <field name="act_to" ref="confirmed"/> <field name="signal">confirm</field> # 【信號】: 通過button觸發, button會根據name去找到相應的signal </record>
實例
# 創建一個recoed時, 會根據工作流模板, 生成工作流實例
有點類似python面向對象的實例化
條件
當條件被滿足時, 自動狀態遷移, 有點類似 (條件+onchange)
自動化的工作流: 設置一個condition
xml示例代碼:
<record model="workflow.transition" id="session_auto_confirm_half_filled"> <field name="act_from" ref="draft"/> <field name="act_to" ref="confirmed"/> <field name="condition">taken_seats > 50</field> </record>
向導
model --> ir.actions.act_window
在odoo中通過使用向導創建一個表單與用戶進行交互, 向導的model使用TransientModel定義
運行wizard: 可以通過ir.actions.act_window模型表里的記錄啟動, 可以從menu里或者某個button觸發;
另外一種方式, 在form view上方的下拉按鈕組(context action)中調用, 設置好src_model關聯對應的model
1 向導視圖中:
src_model 指向上下文的模型 res_model 指向向導的模型 target="new" 將彈出一個新窗口打開向導 special="calcel" 關閉向導窗口而不保存
2 向導模型中
self._context 獲取當前對象的模型的上下文
注意: 向導記錄不是永久性的, 會在一段時間后自動從數據庫中刪除. 這就是為什么他們被稱為"瞬態"
odoo報表
報表構成
1 在ir.actions.report.xml中定義報表記錄, 使用<report>設置報表的各種基本參數
id 外部標示 name 助記符/描述符 model 報告涉及的模型 report_type qweb-pdf/qweb-html report_name 打印出來的名字 groups 允許哪些組可以查看/使用報表 attachment_use 設成True, 報表將使用附件表達式生成的名稱存為記錄的附件 attachment 表達式 paperformat 紙質格式的外部ID, 默認為公司的紙質格式
2 Qweb view定義報表樣式
docs是從context發送過來的變量(上下文), 代表報表內容記錄, user代表打印此報表的人 - external_layout 將在報表上添加默認頁眉和頁腳 - PDF的body將會包含在<div class="page"> - <template>的id必須是<report>里指定的name - <template>里可以使用的變量 docs 記錄當前報表 doc_ids docs 記錄的id列表 doc_model 模型為 docs 記錄 time 引用Python標准庫的 time user res.user 記錄用戶打印報表 res_company 記錄當前 user 的公司
Qweb常用指令
1 數據輸出
t-esc = 'value' 會做html轉義, 有xss攻擊的危險 t-raw 不轉義
2 條件
t-if t-elif t-else
3 循環
t-foreach t-as
t-esc # 設置: t-set = '...' t-value = ''
4 屬性
計算屬性: t-attr
有3中不同的形式:
1 t-attr-$name 2 t-attf-$name 3 t-att-mapping t-att-pair
5 設置變量
通過set指令完成
兩種方式
1 t-value = '2+1' # 可以是表達式 2 如果沒有t-value, 則節點的body將設置為變量的值
6 調用子模版
使用t-call調用其他模版
神奇的0變量
主模版: <div> This template was called with content: <t t-raw="0"/> # 將會渲染為子的內容, 相當於為子的body預留位置 </div> 調用子模版: <t t-call="other-template"> <em>content</em> </t> 將會渲染成: <div> This template was called with content: <em>content</em> </div>
動作
參考 odoo10動作
1 窗口動作
---> ir.actions.act_window
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 表示視圖類型
2 服務器動作
---> ir.actions.server
model_id:當前的動作是在哪個模型上運行的 binding_model_id:綁定的模型,當前動作將會出現在綁定的模型的視圖中 state:服務器動作的類型,總共有 4 種可選的類型,分別是 code(執行 Python 代碼),object_create(創建一條新記錄),object_write(更新記錄),multi(執行多個動作) code:對應 state 的類型 code,為當前動作運行時所要執行的 Python 代碼 我們定義的所有模型都會在 ir.model.data 對應的表中存在相應的記錄 接下來我們再看到字段 code 里面的內容,在這里面我們有一些變量是可以直接使用的: env:Odoo 的運行環境 model:動作觸發時對應的 Odoo 模型實例 record:動作觸發時對應的單個記錄(如在表單視圖中運行對應當前表單所指向的記錄),可能是空的 records:動作觸發時對應的記錄集(如在列表視圖中勾選多條記錄觸發,記錄集指向這些選中的記錄),可能是空的 Python 庫:time, datetime, dateutil, timezone 時間相關的 Python 庫 log:用來記錄日志信息 Warning:通過 raise Warning('xxxxx') 拋出警告信息
3 URL動作
---> ir.actions.act_url
target:有兩個可選值,分別是新窗口(new)打開鏈接,相當於 <a target='_blank' />,以及當前窗口(self)打開,相當於 <a target='_self' /> url:要打開的目標頁面的鏈接,可以是外部頁面也可以是同域下的內部頁面
4 客戶端動作
觸發一個完全右客戶端(瀏覽器)執行的動作
5 報表動作
無
安全與權限
參考 思否文檔參考
1 基於組對表的訪問權限 --> CSV文件
2 基於組對表中數據行的訪問權限 --> XML文件
3 字段級別 // contraint # 通過contraint可以做到字段級別
1 用戶組的權限
模塊分類: ir.module.category
用戶組: res.groups
a 定義用戶組
兩個系統自帶的用戶組:
base.group_user 基礎用戶組
base.user_root 管理員賬號
用戶組里每個字段所代表的含義:
category_id:該用戶組所屬的模塊分類 # <field name="category_id" ref="todo.module_category_todo"/> implied_ids:在當前用戶組下的用戶,同時加入該(字段所指定的)用戶組中 users:該字段所指定的用戶默認被加入到當前用戶組中 # 將會默認獲得此組權限的用戶
b 用戶組的權限
(先根據上一步創建用戶組)
用戶組的權限定義以.csv文件存儲的
默認的權限記錄文件: security/ir.model.access.csv
里面有8個字段, 分別代表的含義如下;
id:這條權限記錄的 id,可以類比為 xml_id # 類似xml的外部標識 name:權限記錄的名稱 model_id:id:要配置權限的模型的外部 ID (以 model_ 開頭) group_id:id:應用此條權限配置的用戶組的 id,若為空則默認對所有用戶組生效 # 上一步創的用戶組id perm_read:讀取記錄的權限,1 為擁有該權限,0 為不分配該權限 perm_write:編輯更新記錄的權限,取值同上 perm_create:創建新記錄的權限,取值同上 perm_unlink:刪除記錄的權限,取值同上
示例
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_app02_contract,app02.contract,model_app02_contract,,1,1,1,0
2 記錄集權限
(俗名: 規則)
模型: ir.rule
model_id:要應用該規則的模型的外部 ID # 模型的外部標識ID --> model_**_** domain_force:過濾條件,符合該條件的記錄都將按照所定義權限進行檢查,其中變量 user 表示當前用戶的實例對象,可以直接使用 groups:應用該規則的用戶組,如果不指定則默認對全部用戶應用該規則
菜單隱藏
只需要在對應的菜單項上添加一個groups屬性即可, 里面的值可以是逗號分隔的多個用戶組的外部ID
