python开发odoo是什么_Odoo开发
Odoo開發入門課程的學生資料, 參考書點擊這里.
概述
利用繼承機制, Odoo可以在不直接修改底層對象的情況下為應用增加特性, 不需要修改已存在的模塊, 而是通過創建新的模塊來實現對模塊的修改. 繼承可以應用在所有的級別, 例如模型, 視圖, 業務邏輯.
本文通過繼承機制為todo_app增加社交和消息特性.
用戶共享特性路線圖為Task模型增加字段, 例如任務的責任人;
修改業務邏輯, 用戶只能操作自己負責的任務, 而不是所有能看到的任務;
視圖添加顯示的字段;
添加社交網絡特性: 消息墻以及關注.
創建模塊框架
創建一個名為todo_user的odoo模塊, 創建__init__.py文件以及__openerp__.py, 修改__openerp__.py文件內容為:
{
'name': 'Multiuser To-Do',
'description': 'Extend the To-Do app to multiuser.',
'author': 'Jeff Zhang',
'depends': ['todo_app'],
}
設置->更新模塊列表->本地模塊查找”todo_user”, 安裝該模塊.
模型擴展
擴展To-Do的模型的說明
Odoo中實體模型使用Python類來定義, 擴展模型時也是使用Python類, 但是需要使用Odoo的一個特殊機制.
為了擴展一個已有的模型, 需要使用一個具有_inherit屬性的Python類來定義. _inherit屬性指明擴展/繼承哪個模型. 新的模型繼承了父模型的所有特性, 在新類中定義我們期望的特性即可.
在Odoo中, 模型是獨立于特定模塊的, 可以通過self.env[]獲得模型的引用. 例如模型res.partner的引用可以使用self.env[‘res.partner’]獲得.
當服務啟動后模塊載入時, 任何擴展的模型修改只會影響之前載入的模塊, 所以載入順序很重要需要確認模塊依賴關系是正確的.
向模型增加一個字段
擴展todo.task模型, 增加以下字段: 任務的責任人, 最后期限日期.
創建models子目錄, 并在其中創建todo_task.py文件, 內容如下:
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from openerp import models, fields, api
class TodoTask(models.Model):
_inherit = 'todo.task'
user_id = fields.Many2one('res.users', 'Responsible')
date_deadline = fields.Date('Deadline')
注意_inherit屬性, 此處其值為’todo.task’, 說明這個類繼承自todo.task模型. 使用了_inherit屬性, 那么_name屬性不需要了.
在models下創建__init__.py文件, 內容如下:
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import todo_task
在模塊根目錄下的__init__.py中增加:
from models import todo_task
更新模塊, 在技術特性中查看模型, 可以看到模型todo.task中增加了的新字段.
修改已存在的字段
除了通過繼承增加新的字段, 自odoo8.0開始, 還可以修改已存在的字段的屬性, 只需簡單地添加相同名稱的字段并設置字段屬性值即可.
例如, 為了改變name字段的help tooltip, 在todo_task.py中增加一句即可:
name = fields.Char(help="What needs to be done?")
升級模塊, 查看模型, 可以發現修改后的變化.
修改模型的方法
繼承還可以應用在業務邏輯上, 例如向模型添加新的方法, 簡單地在派生類中定義相應的函數即可.
覆蓋已有的業務邏輯
如果希望擴展已存在的業務邏輯, 可以定義一個同名的方法覆蓋已有模型中的方法, 并且在這個派生類的方法中還可以使用Python的super關鍵字來訪問其覆蓋的父方法.
示例: 覆蓋To-Do應用模型中的do_clean_done方法, 該方法之前的業務邏輯是將所有is_done為True的記錄的active字段賦值為False, 原來的代碼如下:
@api.multi
def do_clear_done(self):
done_recs = self.search([('is_done', '=', True)])
done_recs.write({'active': False})
return True
由于現在希望每個用戶只能操作他自己的任務, 所以需要修改do_clean_done的業務邏輯, 修改后的代碼如下:
@api.multi
def do_clear_done(self):
domain = [('is_done', '=', True),
'|', ('user_id', '=', self.env.uid),
('user_id', '=', False)]
done_recs = self.search(domain)
done_recs.write({'active': False})
return True
發生的修改很簡單, 就是將之前的記錄過濾條件由僅僅考慮is_done為True改為is_done為True并且user_id為當前用戶或user_id為空(False).
odoo中過濾條件使用一個domain來描述, 一個domain用包含多個條件的列表來描述. 每個條件用一個元組來表示, 各個條件之間為’與’的關系. 如果希望表達’或’的關系, 先使用’|’, 在’|’后面的兩個元組為’或’關系的兩個條件表達式.
這樣, 新的方法覆蓋了父方法. 更新并升級模塊, 還看不出效果, 因為現在所有任務的user_id還都是False.
改進已有的業務邏輯
除了上例中完整的替換某個業務邏輯外, 更多的情況是在不破壞已有業務邏輯并利用它的情況下擴展它, 比如增加預處理或后處理等. 下面的代碼在現有的標記任務完成的業務邏輯基礎上, 增加一個用戶身份的判斷:
@api.one
def do_toggle_done(self):
if self.user_id != self.env.user:
raise Exception('Only the responsible can do this!')
else:
return super(TodoTask, self).do_toggle_done()
使用Python的super()方法可以調用父類中的方法, super相關信息如下:
Help on class super in module __builtin__:
class super(object)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj, type)
| super(type, type2) -> bound super object; requires issubclass(type2, type)
| Typical use to call a cooperative superclass method:
| class C(B):
| def meth(self, arg):
| super(C, self).meth(arg)
視圖擴展
基本視圖擴展
在odoo中, 視圖繼承的形式如下:
Todo Task form – User extension
todo.task
inherit_id域指定欲擴展的視圖, 它的ref屬性用來指定欲擴展視圖的外部ID.
外部ID跨模塊地唯一標識一個資源, 更多的信息在后續的內容中介紹.
Form, Tree/List以及Search視圖都是使用arch的XML結構來定義的, 為了修改這個XML, 需要定位XML元素. 在XML中定位元素最直接的方法是使用XPath表達式, 例如這個元素可以使用下面的表達式來定位:
//field[@name]='is_done'
在此基礎上, 如果希望在is_done之前增加date_deadline字段, 可以使用下面的XML實現:
除了XPath外, odoo還提供了更加方便的標記方法, 可以避免使用XPath, 上面的XML可以用簡化為下面的內容:
用于確定新字段顯示位置的定位, 除此之外, , ,
等都有類似特性.相應地, name屬性是經常用到的資源查找方式, 但是也可以使用其他的方式, 例如如果需要查找顯示某些特定字符串的label或者CSS類名, 就可以使用string.
position屬性用于指定新增元素的位置, 可以有以下的選擇:
1.after: 在匹配元素之后, 與匹配元素具有相同的父元素;
2.befor: 在匹配元素之前, 與匹配元素具有相同的父元素;
3.inside(默認值): 作為匹配元素內容;
4.replace: 替換匹配元素的內容, 如果值為空將會刪除匹配的元素;
5.attributes: 修改匹配元素的屬性.
position屬性的這幾種可選值大部分容易理解, 只對attributes進行說明. 如果position屬性設定為attributes, 那么需要使用value設定該屬性的新值. 例如下面的代碼將invisible屬性設置為1:
1
新建一個views文件夾, 在其中新增一個todo_view.xml文件, 將基本視圖擴展代碼寫入其中:
Todo Task form – User extension
todo.task
I have to...
最后, 在__openerp__.py中增加data描述:
'data': ['views/todo_view.xml'],
更新模塊, 創建新任務, 發現新增特性已經應用了, 如下圖.
新增一個任務, 然后設定為完成, 切換到管理員角色可以看到包括已完成任務在內的所有任務, 但是現在點擊清除已完成任務, 不會將非admin用戶的任務的activity設置為False, 滿足預期的業務邏輯要求.
但現在存在一個問題: 如果使用admin用戶創建一個任務, 并將Responsible設定為另一個用戶(例如aaa), 以aaa登錄并不能看到這個由admin分配的任務. 這是由于之前設定了行級訪問規則, 其中的下面這一句設定導致不能顯示, 這個問題在本文最后一部分解決.
[('create_uid','=',user.id)]
List/Tree視圖和搜索視圖擴展
向todo_view.xml中增加下面的內容擴展List/Tree視圖:
Todo Task tree – User extension
todo.task
向todo_view.xml中增加下面的內容擴展搜索視圖:
Todo Task tree – User extension
todo.task
domain="[('user_id','in',[uid,False])]" />
domain="[('user_id','=',False)]" />
更新模塊, 看效果.
關于擴展模型的更多討論
前面介紹的模型繼承是最基本的模型繼承方式, 但是還有更強力的混合類繼承和代理繼承方式. 前者通過繼承將某個模型的所有功能特性加入另一個模型中, 后者通過一種透明的方式訪問另一個模型中的數據.
利用原型繼承實現模型特性的拷貝
之前使用_inherit屬性來擴展一個模型, 定義一個繼承todo.task模型的類, 然后向該其添加了一些特性, 這種方法中類的_name屬性沒有進行設定, 仍然是todo.task.
如果使用模型的_name屬性, 可以創建混合類(mixin class).
from openerp import models
class TodoTask(models.Model):
_name = 'todo.task'
_inherit = 'mail.thread'
以上代碼將模型mail.thread的特性拷貝到模型todo.task, 使todo.task具有了mail.thread的功能特性. mail.thread實現了消息和關注功能, 這個功能是可重用的, 所以可以非常方便地將該特性添加到其他模型上.
上面提到的拷貝意味著繼承的新模型中可以獲得被繼承的所有字段和方法, 也即被繼承模型中的字段也將在繼承的新模型對應的數據庫表中創建, 并且新模型中也包括未繼承前的所有字段. 舊模型和繼承后的新模型的數據被分別保存, 不會產生沖突. 下圖是一個示意圖.
上圖中最上方可以看到一個名為”gogogo”的任務中, 用戶aaa發送了兩條消息給所有關注該任務的用戶. 在數據庫的todo_task表(舊模型)中, 只保存舊的字段, 而社交網絡數據則保存在mail_message表(新模型中包括)中并與todo_task中的記錄關聯起來.
混合模型一般用于抽象模型, 例如mail.thread. 抽象模型與通常的模型類似, 只是抽象模型不在數據庫中創建相應的數據表, 所以抽象模型更像是一個模板, 描述重用于普通模型時的字段和業務邏輯, 抽象模型中定義的字段只會在繼承自它的普通模型中創建.
一般使用混合(mixin)繼承時, 很少繼承自普通模型, 因為這種繼承機制將會復制相同的數據結構. 如果必須繼承普通模型, 那么應該使用odoo提供你的代理繼承機制, 這種機制能夠避免數據結構的復制.
使用代理繼承嵌入模型
代理繼承使用_inherits屬性(多一個s)將繼承的模型映射到字段.
from openerp import models, fields
class User(models.Model):
_name = 'res.users'
_inherits = {'res.partner': 'partner_id'}
partner_id = fields.Many2one('res.partner')
例如以上的代碼是標準的Users模型(res.users), 其中嵌入了了一個Partner模型. 當創建一個新的User時, 一個Partner將會同時創建, 并且partner_id中將會保存這個Partner的引用, 這種機制類似OO中的多態概念.
嵌入的模型(Partner)中的所有字段就像是User的字段一樣, 可以以相同的形式直接使用. 例如, partner的name和address字段使用起來與使用User本身的字段一樣, 只不過它們的數據實際上保存在關聯的Partner模型中. 這樣沒有數據結構的復制.
注意, 代理繼承中只有字段被繼承, 方法是不能繼承的!
為TODO應用增加社交網絡功能
基本步驟
社交網絡模塊(技術名稱mail)提供的消息板可以在很多頁面的底部看到, 也被稱作Open Chatter.
社交網絡消息功能通過mail模塊的mail.thread模型提供, 這是一個抽象模型, 可以用以下步驟將其添加到其他模型:
Step 1. 模塊中添加對mail模塊的依賴;
Step 2. 模型集成于mail.thread模型;
Step 3. 向該模型的form視圖中添加Followers和Thread widgets;
Step 4. 為followers設定行級訪問規則(可選).
Step1 to Step3
Step1, todo_task依賴于todo_app, 而todo_app依賴于mail, 所以不需要再做;
Step2, 之前我們的模型已經使用_inherit繼承了todo.task模型, 因為odoo的_inherit可以接受多個模型繼承, 使用列表即可, 所以對todo_task.py進行如下修改:
由:
_inherit = 'todo.task'
改為:
_name = 'todo.task'
_inherit = ['todo.task', 'mail.thread']注意: 創建抽象模型: 派生自models.AbstractModel而不是models.Model即可.
Step3, 使用視圖繼承將社交網絡小組件(widgets)擺放在form底部, 打開todo_view.xml, 添加下面的內容到view_form_todo_task_inherited的arch部分:
message_follower_ids和message_ids這兩個字段在mail.thread模型中定義.
更新模塊, 看效果. 關注一個任務, 然后登錄其他用戶打開這個任務, 在下方的社交組件處向關注這個任務的用戶發送消息, 其他所有關注該任務的用戶都可以收到這條消息了.
修改菜單項
與視圖不同, 一般數據記錄沒有XML的arch結構, 所以不能通過XPath表達式擴展和修改. 想要修改這些數據, 需要使用另一種方式.
利用可以完成模型上的插入或更新操作: 如果x不存在, 插入記錄; 否則, 對其進行更新.
例如下面的代碼修改菜單項, 將其添加到todo_user模塊的todo_view.xml中:
My To-Do
id="todo_app.action_todo_task">
{'search_default_filter_my_tasks': True}
Step4, 修改行級訪問規則
在之前的To-Do引用中, 應用了一條行級訪問規則, 使得任務只對創建它的用戶可見, 但是現在增建了社交網絡, 用戶之間可以加入協作, 任務需要對其他的用戶可見, 例如被分配為任務責任人的讓用戶或關注任務的用戶.
這里需要做的工作于上一節修改菜單項類似: 重寫todo_app.todo_task_user_rule, 修改domain_force字段為新的值(現在是任務創建用戶ID與當前用戶相同). 但是由于todo_app中設定了, 所以不能進行寫操作, 這里需要做的是: 刪除之前的行級訪問規則并且創建一個新的.
為了保持模塊組織性, 新建一個security子目錄并在其中創建一個名為todo_access_rules.xml的文件, 內容如下:
ToDo Tasks only for owner
eval="[(4, ref('base.group_user'))]"/>
['|',('user_id','in', [user.id,False]),
('message_follower_ids','in',[user.partner_id.id])]
以上代碼首先刪除已有的todo_task_user_rule記錄, 然后創建一條新的記錄.需要注意的是對于Followers的處理, 因為followers是partners, 并不是User對象, 所以需要使用user.partner_id.id而不是user.id.
還可以在開發時將改為, 正式發布時再改回來.
最后, 修改__openerp__.py中的data屬性:
'data': [
'views/todo_view.xml',
'security/todo_access_rules.xml',
],
更新模塊, 看效果吧, 之前提到的由于行級訪問控制規則引起的現象沒有了, 一切都如計劃運行.
總結
以上是生活随笔為你收集整理的python开发odoo是什么_Odoo开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 亚马逊后台操作不容措施旺季~~~~~~
- 下一篇: C++简易计算器的实现