1. 程式人生 > >Odoo中Qweb使用入門

Odoo中Qweb使用入門

sage cli one ali http input 更新 對象實例 blog

參考

可參考官網例子https://doc.odoo.com/trunk/web/qweb/或

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

1 Qweb官方定義

Qweb被用作OpenERP的Web客戶端模板引擎。它是一種基於XML的模板語言,同Genshi, Thymeleaf、Facelets模板具有相似並且具有以下特性:

完全在客戶端瀏覽器中完成渲染;

一個模板文件中可以包含多個模板,通常一個模板文件中包含一個模板;

對OpenERP的web組件有很好的支持,也可以用於除開OpenERP web外的其他框架。

2 OpenERP中使用Qweb

2.1 獲取Odoo中由Bazaar管理的Qweb例子源代碼

bzr branch lp:~niv-openerp/+junk/oepetstore -r 1-Ossl.cert_reqs=none

從python安裝路勁下的Script目錄中復制項目oepetstore到OpenERP的插件(addons)目錄下,啟動OpenERP,更新並安裝oepetstore模塊:

完成後在Chrome瀏覽器下訪問http://localhost:8069/ 依次點擊菜單:Pet Store àHome Page

點擊無效,系統會提示。

這是由於定義在__openerp__.py文件中定義模塊需要加載的petstore.js沒被引用到系統。

暫時沒找到原因,我用的是odoo_8.0rc1-latest版本,不知道是不是版本從7升級到8後的變化,解決方法:

在模塊目錄下建立xml文件(名稱可隨便取如link.xml),通過指定路勁引入js和css,

然後修改模塊定義中data內容增加link.xml引用。(至於js和css此處沒有生效,可去掉裏面的引用)。

link.xml 內容:

<?xml version="1.0"encoding="utf-8"?>

<!-- vim:fdn=3:

-->

<openerp>

<data>

<template id="assets_backend"

name="petstore" inherit_id="web.assets_backend">

<xpath expr="."position="inside">

<link rel="stylesheet" href="/oepetstore/static/src/css/petstore.css"/>

<script type="text/javascript"src="/oepetstore/static/src/js/petstore.js"></script>

</xpath>

</template>

</data>

</openerp>

完成後重啟系統,升級模塊,再次點擊菜單:Pet Store àHomePage ,在控制臺下出現“petstore home page loaded”則表示模塊已經運行成功:

到此Qweb還沒開始使用,這僅僅是通過odoo的簡單的應用了Widget組件。

官方對Widget定義,參考:https://doc.odoo.com/trunk/web/widget/

class openerp.web.Widget()

這是odoo中所有的可視化組件的基類。它對應於一個MVC視圖。它處理部分的網頁提供一系列的服務:

通過Qweb進行渲染;

繼承關系;

生命周期管理(包括當父對象被刪除子類的摧毀);

DOM文檔插入操作,通過jQuery插入方法。插入對象可以是任何相應的jQuery方法(一般選擇器,DOM節點和jQuery對象)。

2.2 通過Qweb結合Widget組件運用

目標:

點擊左側菜單,查詢模塊例子中表message_of_the_day的數據,通過Qweb以列表形式呈現。

(通過例子中自帶的菜單添加一些假數據)

2.2.1 編寫js代碼

在static/src/js/petstore.js中添加

// MessageListPage部件擴展自Widget基類

instance.oepetstore.MessageListPage = instance.web.Widget.extend({

template: "message",//模板根節點(同xml模板文件中對應)

init: function() {

this._super.apply(this, arguments);

},

start: function() {

var self = this;

//message_of_the_day 表對應的模塊名稱

//query加上字段查詢指定列,不加可以查詢所有列

// query().all()查詢所有數據

//query().first()查詢第一條

new instance.web.Model("message_of_the_day").query(["message","create_date"]).all().then(function(result) {

var ss= result.message + result.create_date

//messageList 把得到的result josn數組,通過Qweb標簽解析到名稱為messageList(同xml模板文件中對應)的模板,模板標簽對msgList進行遍歷

self.$el.append($(QWeb.render("messageList",{msgList: result})));

$(".button-view").click(function(e){

alert("view..");

});

$(".button-edit").click(function(e){

alert("edit..");

});

$(".button-cancel").click(function(e){

alert("cancel..");

});

});

},

});

instance.web.client_actions.add(‘petstore.messagemenu‘,‘instance.oepetstore.MessageListPage‘);

2.2.2編寫xml模板文件

static/src/xml/message.xml

<?xml version="1.0"encoding="UTF-8"?>

<templates xml:space="preserve">

<t t-name="message">

<div class="oe_petstore_pettoyslist">

</div>

</t>

<t t-name="messageList">

<table class="oe_list_content">

<thead>

<tr>

<th class="oe_list_header_textoe_sortable">消息</th>

<th class="oe_list_header_textoe_sortable">創建時間</th>

<th>操作</th>

</tr>

</thead>

<t t-foreach="msgList"t-as="bo">

<tr class="oe_list_header_columns">

<td class="oe_list_field_celloe_list_field_text" ><t t-esc="bo.message"/></td>

<td class="oe_list_field_celloe_list_field_text" ><t t-esc="bo.create_date"/></td>

<td>

<a class="button-view" t-att-data="bo.id" name="detailBtn"href="#" ><i class="icon-zoom-in"></i>詳情</a>

<a class="button-edit" t-att-data="bo.id" name="traceOrderBtn" href="javascript:void(0);"><iclass="fa fa-pencil"></i>編輯</a>

<a class="button-cancel" t-att-data="bo.id" class="red"name="cancelOrderBtn" href="javascript:void(0);"><i class="glyphicon glyphicon-remove"></i>取消</a>

</td>

</tr>

</t>

</table>

</t>

</templates>

此處我添加了一些odoo自帶的css樣式,在每列數據後面添加了幾個可以操作的按鈕(此處按鈕功能未實現,僅提供樣式)

2.2.3 在模塊跟路徑下petstore.xml中添加菜單鏈接和動作

<record id="message_day_action"model="ir.actions.client">

<field name="name">信息列表</field>

<field name="tag">petstore.messagemenu</field>

</record>

<menuitem id="message_day_action_menu"name="QwebMessageList" parent="petstore_menu" action="message_day_action"/>

通過Qweb對數據簡單列表查詢已經完成,重啟Odoo,升級模塊,依次點擊菜單Pet Store àQwebMessageList,結果如下:

小提示:

1、一個模塊中

openerp.oepetstore = function(instance) {

}該函數實例只能定義一個,並且為openerp.模塊名稱(必須跟模塊名稱一樣,否則該js不能正確的被引入)

2、static目錄下定義的js、css和xml模板改變了模塊不需升級。

2.3關鍵點說明

2.3.1 QWeb模板引擎

QWeb模板在XML屬性上加前綴“t-”表示:

t-name:模板名稱,如:

<t t-name="message"></t>

t-foreach=iterable:循環遍歷標簽

<tt-foreach="msgList" t-as="bo"> </t>

t-esc:引用實例參數,可以使用任意JavaScript表達式;如

<tt-esc="bo.message"/>

t-att-attName:對象屬性設置,如對input輸入控件設置value:

<inputtype="text" t-att-value="order.buyer_memo"/>

其他更多標簽可以參考https://doc.odoo.com/trunk/web/qweb/下 Defining Templates 節點

2.3.2 與服務器的交互-讀取數據 (call 和query)

客戶端使用Ajax與服務器交互,不過OpenERP框架提供了簡化的方法,通過數據模型進行訪問。OpenERP自動將服務端的數據模型轉化為客戶端端模型,直接調用即可。服務器上petstore.py裏面的模型

call()方法應用:

客戶端調用:

instance.oepetstore.HomePage =instance.web.Widget.extend({

start: function() {

var self = this;

var model = new instance.web.Model("message_of_the_day");

model.call("my_method",[],{context:newinstance.web.CompoundContext()}).then(function(result) {

self.$el.append("<div>Hello " +result["hello"] + "</div>");

});//通過讀取到服務端數據展示在頁面。

},

});

模型的call()方法參數:
第一個參數name是方法的名稱;
第二個參數args是按照順序排列的參數數組。OpenERP定義的模型方法前三個參數(self, cr, uid)是固定的,由框架產生,也就是說傳遞的參數數組從第四個開始插入。而context又是特殊的。

例子:方法定義:

def my_method2(self, cr, uid, a, b, c,context=None):

調用:

model.call("my_method", [1, 2,3], ...// with this a=1, b=2 and c=3

第三個參數kwargs為命名參數,按照名稱傳遞給Python的方法參數。例如:

model.call("my_method",[], {a: 1, b: 2, c: 3}, ...// with this a=1, b=2 and c=3

OpenERP模型中的context是一個特殊參數,表示調用者的上下文,一般就使用客戶端WebClient實例提供的instance.web.CompoundContext()類新建一個對象實例即可。CompoundContext類提供用戶的語言和時區信息。也可以在構造函數中添加另外的數據:

model.call("my_method",[], {context: new instance.web.CompoundContext({‘new_key‘: ‘key_value‘})})defdisplay_context(self, cr, uid, context=None): print context // will print:{‘lang‘: ‘en_US‘, ‘new_key‘: ‘key_value‘, ‘tz‘: ‘Europe/Brussels‘, ‘uid‘: 1}

query()方法應用

本例中使用的mode的query方法

var model = new instance.web.Model("message_of_the_day");

model.query(["message","create_date"]).

filter([[id,‘=‘,1], [‘company_id‘, ‘=‘, main_company]])

.limit(15).all().then(function(result) {

self.$el.append($(QWeb.render("messageList", {msgList:result})));

});

model: 數據模型的query()方法的參數是需要讀取的模型字段名稱列表;該方法返回的是一個instance.web.Query()類型的查詢對象實例,包括一些進一步定義查詢結果的方法,這些方法返回的是同一個查詢對象自身,因此可以鏈接:

filter():指定OpenERP 域(domain),也即過濾查詢結果;limit():限制返回的記錄數量。最後調用查詢對象的all()方法執行查詢。查詢異步執行,all()返回的是一個deferred,因此要用then()提供回調函數來處理結果。數據模型的查詢是通過rpc調用實現的。

self.$el得到模板中定義的message的根節點(div),append()方法將處理完成的頁面內容賦值到根節點下。

$(QWeb.render("messageList",{msgList: result}))則是把result數組傳遞到模板為messageList中的msgList對象(此處是傳遞到該對象並進行遍歷),返回完整的頁面內容html代碼。

Odoo中Qweb使用入門