转自:http://blog.csdn.net/mackz/article/details/22581517

在7和8下测试均可。

  1.相关库/框架
  主要:jQuery(使用1.8.3,如果使用新版本,其他jQuery插件也要升级或修改)、Underscore、QWeb
  其他:都在addons\web\static\lib路径下。

  2.示例框架
  下载(需要先安装bzr):bzr branch lp:~niv-openerp/+junk/oepetstore -r 1
  下载后将路径加到OpenERP服务器的addons_path参数中,重启服务器、更新模块列表再安装。
  在__openerp__.py中通过:

'js': ['static/src/js/*.js'],
'css': ['static/src/css/*.css'],
'qweb': ['static/src/xml/*.xml'],

将所有js/css/xml(QWeb模板)文件包含进来。
  oepetstore/static/js/petstore.js注释说明:

openerp.oepetstore = function(instance) { // OpenERP模型,必须和模块名称相同。instance参数是OpenERP Web Client自动加载模块时传入的实例。
var _t = instance.web._t,
_lt = instance.web._lt; // 翻译函数
var QWeb = instance.web.qweb; // QWeb实例 instance.oepetstore = {}; // instance实例里面的模块命名空间(namespace),比如和模块名称相同。 instance.oepetstore.HomePage = instance.web.Widget.extend({ // 自定义首页部件
start: function() { // 部件创建时自动调用的方法
console.log("pet store home page loaded");
},
}); instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');
// 将自定义首页部件与菜单动作绑定
}

可以在网址后面加“?debug”参数使脚本不压缩以便于调试,例如:

http://localhost:8069/?debug

3.类的定义
  从instance.web.Class基类扩展:

instance.oepetstore.MyClass = instance.web.Class.extend({
say_hello: function() {
console.log("hello");
},
});
var my_object = new instance.oepetstore.MyClass();
my_object.say_hello();

构造函数名为init();使用this访问对象实例的属性或方法:

instance.oepetstore.MyClass = instance.web.Class.extend({
init: function(name) {
this.name = name;
},
say_hello: function() {
console.log("hello", this.name);
},
}); var my_object = new instance.oepetstore.MyClass("Nicolas");
my_object.say_hello();

类可以通过extend()方法继承;使用this._super()调用基类被覆盖的方法。

instance.oepetstore.MySpanishClass = instance.oepetstore.MyClass.extend({
say_hello: function() {
this._super();
console.log("translation in Spanish: hola", this.name);
},
}); var my_object = new instance.oepetstore.MySpanishClass("Nicolas");
my_object.say_hello();

4.部件(Widget)
  从instance.web.Widget扩展自定义部件。HomePage首页部件见petstore.js。
  在自定义部件中,this.$el表示部件实例的jQuery对象,可以调用jQuery方法,例如:

this.$el.append("<div>Hello dear OpenERP user!</div>");

往部件中添加一个<div>块及内容。
  部件中可以插入其他部件进行组合:

instance.oepetstore.GreetingsWidget = instance.web.Widget.extend({
start: function() {
this.$el.addClass("oe_petstore_greetings");
this.$el.append("<div>We are so happy to see you again in this menu!</div>");
},
});
instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
this.$el.addClass("oe_petstore_homepage");
this.$el.append("<div>Hello dear OpenERP user!</div>");
var greeting = new instance.oepetstore.GreetingsWidget(this); // 创建部件的时候传入父部件的实例作为构造参数。
greeting.appendTo(this.$el);
},
});

父子部件可以通过getChildren()、getParent()进行互相访问。如果重载部件的构造函数,第一个参数必须是父部件,并且必须传递给基类。

instance.oepetstore.GreetingsWidget = instance.web.Widget.extend({
init: function(parent, name) {
this._super(parent);
this.name = name;
},
});

如果作为顶层部件创建,parent参数应该是null。
  部件实例可以调用destroy()方法销毁。

  5.QWeb模板引擎
  QWeb模板在XML属性上加前缀“t-”表示:
    t-name:模板名称;
    t-esc:引用实例参数,可以使用任意JavaScript表达式;
    t-raw:引用原始实例参数,如果有html标记则保留。
  QWeb模板下面的根元素最好只有一个。
  oepetstore/static/src/xml/petstore.xml:

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

<templates xml:space="preserve">
<t t-name="HomePageTemplate">
<div style="background-color: red;">
<div>Hello <t t-esc="name"/></div>
<div><t t-esc="3+5"/></div>
<div><t t-raw="some_html"/></div>
</div>
</t>
</templates>

定义一个名为“HomePageTemplate”的模板。
  使用方法1:

instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
this.$el.append(QWeb.render("HomePageTemplate"));
},
});

使用方法2:

instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePageTemplate",
start: function() {
...
},
});

模板里面的条件控制t-if:

        <t t-if="true == true">
true is true
</t>
<t t-if="true == false">
true is not true
</t>

枚举t-foreach和t-as:

        <t t-foreach="names" t-as="name">
<div>
Hello <t t-esc="name"/>
</div>
</t>

属性赋值,在属性名前加前缀“t-att-”:

<input type="text" t-att-value="defaultName"/>

将input控件的value属性赋值为“defaultName”。
  部件开发示例,显示产品列表。
  JavaScript脚本:

openerp.oepetstore = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb; instance.oepetstore = {}; instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
var products = new instance.oepetstore.ProductsWidget(this, ["cpu", "mouse", "keyboard", "graphic card", "screen"], "#00FF00");
products.appendTo(this.$el);
},
}); instance.oepetstore.ProductsWidget = instance.web.Widget.extend({
template: "ProductsWidget",
init: function(parent, products, color) {
this._super(parent);
this.products = products;
this.color = color;
},
}); instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');
}

QWeb模板:

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

<templates xml:space="preserve">
<t t-name="ProductsWidget">
<div>
<t t-foreach="widget.products" t-as="product">
<span class="oe_products_item" t-att-style="'background-color: ' + widget.color + ';'"><t t-esc="product"/></span><br/>
</t>
</div>
</t>
</templates>

CSS样式:

.oe_products_item {
display: inline-block;
padding: 3px;
margin: 5px;
border: 1px solid black;
border-radius: 3px;
}

6.部件事件与特性

instance.oepetstore.ConfirmWidget = instance.web.Widget.extend({
start: function() {
var self = this;
this.$el.append("<div>Are you sure you want to perform this action?</div>" +
"<button class='ok_button'>Ok</button>" +
"<button class='cancel_button'>Cancel</button>");
this.$el.find("button.ok_button").click(function() { // 在按钮上绑定click事件
self.trigger("user_choose", true); // 触发自定义user_choose事件,传递事件参数true/false
});
this.$el.find("button.cancel_button").click(function() {
self.trigger("user_choose", false);
});
},
}); instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
var widget = new instance.oepetstore.ConfirmWidget(this);
widget.on("user_choose", this, this.user_choose); // 在部件上绑定user_choose事件到响应函数user_choose
widget.appendTo(this.$el);
},
user_choose: function(confirm) {
if (confirm) {
console.log("The user agreed to continue");
} else {
console.log("The user refused to continue");
}
},
});

部件特性(Properties)的使用:

    this.widget.on("change:name", this, this.name_changed); //绑定name特性的change事件
this.widget.set("name", "Nicolas"); // 设置特性值
var getedname = this.widget.get("name"); // 读取特性值

7.部件访问  简化jQuery选择器:

this.$el.find("input.my_input")

等于

this.$("input.my_input")

因此事件的绑定:

this.$el.find("input").change(function() {
self.input_changed();
});

可以简化为:

this.$(".my_button").click(function() {
self.button_clicked();
});

进一步,可以通过部件提供的events字典属性简化为:

instance.oepetstore.MyWidget = instance.web.Widget.extend({
events: {
"click .my_button": "button_clicked",
},
button_clicked: function() {
..
}
});

注意:这种方法只是绑定jQuery提供的DOM事件机制,不能用于部件的on语法绑定部件自身的事件。  event属性的键名由两部分组成:事件名称和jQuery选择器,用空格分开。属性值是响应事件的函数(方法)。
  事件使用示例:
  JavaScript脚本:

openerp.oepetstore = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb; instance.oepetstore = {}; instance.oepetstore.ColorInputWidget = instance.web.Widget.extend({
template: "ColorInputWidget",
start: function() {
var self = this;
this.$el.find("input").change(function() {
self.input_changed();
});
self.input_changed();
},
input_changed: function() {
var color = "#";
color += this.$el.find(".oe_color_red").val();
color += this.$el.find(".oe_color_green").val();
color += this.$el.find(".oe_color_blue").val();
this.set("color", color);
},
}); instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePage",
start: function() {
this.colorInput = new instance.oepetstore.ColorInputWidget(this);
this.colorInput.on("change:color", this, this.color_changed);
this.colorInput.appendTo(this.$el);
},
color_changed: function() {
this.$el.find(".oe_color_div").css("background-color", this.colorInput.get("color"));
},
}); instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');
}

QWeb模板:

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

<templates xml:space="preserve">
<t t-name="ColorInputWidget">
<div>
Red: <input type="text" class="oe_color_red" value="00"></input><br />
Green: <input type="text" class="oe_color_green" value="00"></input><br />
Blue: <input type="text" class="oe_color_blue" value="00"></input><br />
</div>
</t>
<t t-name="HomePage">
<div>
<div class="oe_color_div"></div>
</div>
</t>
</templates>

CSS样式:

.oe_color_div {
width: 100px;
height: 100px;
margin: 10px;
}

  8.修改已有的部件和类
  可以用include()方法重载已有的部件和类,这个和继承机制类似,是一种插入的方法:

var TestClass = instance.web.Class.extend({
testMethod: function() {
return "hello";
},
}); TestClass.include({
testMethod: function() {
return this._super() + " world";
},
}); console.log(new TestClass().testMethod());
// will print "hello world"

应尽量避免使用这种机制导致的复杂性。

  9.与服务器的交互-读取数据模型
  客户端使用Ajax与服务器交互,不过OpenERP框架提供了简化的方法,通过数据模型进行访问。
  OpenERP自动将服务端的数据模型转化为客户端端模型,直接调用即可。服务器上petstore.py里面的模型:

class message_of_the_day(osv.osv):
_name = "message_of_the_day" def my_method(self, cr, uid, context=None):
return {"hello": "world"} _columns = {
'message': fields.text(string="Message"),
'color': fields.char(string="Color", size=20),
}

客户端调用例子:

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: new instance.web.CompoundContext()}).then(function(result) {
self.$el.append("<div>Hello " + result["hello"] + "</div>");
// will show "Hello world" to the user
});
},
});

模型的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是一个特殊参数,表示调用者的上下文,一般就使用客户端Web Client实例提供的instance.web.CompoundContext()类新建一个对象实例即可。
  CompoundContext类提供用户的语言和时区信息。也可以在构造函数中添加另外的数据:

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

(OpenERP服务器端数据模型的方法必须提供4个参数:self, cr, uid, context=None,分别表示模型实例、数据库指针(Cursor)、用户id和用户上下文)

  10.与服务器的交互-查询
  客户端数据模型提供了search()、read()等方法,组合为query()方法,使用例子:

model.query(['name', 'login', 'user_email', 'signature'])     .filter([['active', '=', true], ['company_id', '=', main_company]])     .limit(15)     .all().then(function (users) {    // do work with users records});

数据模型的query()方法的参数是需要读取的模型字段名称列表;该方法返回的是一个instance.web.Query()类型的查询对象实例,包括一些进一步定义查询结果的方法,这些方法返回的是同一个查询对象自身,因此可以链接:
    filter():指定OpenERP 域(domain),也即过滤查询结果;
    limit():限制返回的记录数量。
  最后调用查询对象的all()方法执行查询。
  查询异步执行,all()返回的是一个deferred,因此要用then()提供回调函数来处理结果。
  数据模型的查询是通过rpc调用实现的。
  示例1:显示每日提示
  JavaScript脚本:

openerp.oepetstore = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb; instance.oepetstore = {}; instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePage",
start: function() {
var motd = new instance.oepetstore.MessageOfTheDay(this);
motd.appendTo(this.$el);
},
}); instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage'); instance.oepetstore.MessageOfTheDay = instance.web.Widget.extend({
template: "MessageofTheDay",
init: function() {
this._super.apply(this, arguments);
},
start: function() {
var self = this;
new instance.web.Model("message_of_the_day").query(["message"]).first().then(function(result) {
self.$(".oe_mywidget_message_of_the_day").text(result.message);
});
},
}); }

QWeb模板:

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

<templates xml:space="preserve">
<t t-name="HomePage">
<div class="oe_petstore_homepage">
</div>
</t>
<t t-name="MessageofTheDay">
<div class="oe_petstore_motd">
<p class="oe_mywidget_message_of_the_day"></p>
</div>
</t>
</templates>

CSS样式:

.oe_petstore_motd {
margin: 5px;
padding: 5px;
border-radius: 3px;
background-color: #F0EEEE;
}

示例2:组合显示每日提示和产品列表
  服务器端从OpenERP的产品表继承一个类(模型):

class product(osv.osv):
   _inherit = "product.product"
  
   _columns = {
   'max_quantity': fields.float(string="Max Quantity"),
   }

因此数据是保存在product.product表中的,只是扩充了一个“max_quantity”字段;这个例子结合前面的每日提示信息,显示二列,左面一列显示产品列表,右面显示提示信息。
  JavaScript脚本:

openerp.oepetstore = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb; instance.oepetstore = {}; instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePage",
start: function() {
var pettoys = new instance.oepetstore.PetToysList(this);
pettoys.appendTo(this.$(".oe_petstore_homepage_left"));
var motd = new instance.oepetstore.MessageOfTheDay(this);
motd.appendTo(this.$(".oe_petstore_homepage_right"));
},
}); instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage'); instance.oepetstore.MessageOfTheDay = instance.web.Widget.extend({
template: "MessageofTheDay",
init: function() {
this._super.apply(this, arguments);
},
start: function() {
var self = this;
new instance.web.Model("message_of_the_day").query(["message"]).first().then(function(result) {
self.$(".oe_mywidget_message_of_the_day").text(result.message);
});
},
}); instance.oepetstore.PetToysList = instance.web.Widget.extend({
template: "PetToysList",
start: function() {
var self = this;
new instance.web.Model("product.product").query(["name", "image"])
.filter([["categ_id.name", "=", "Pet Toys"]]).limit(5).all().then(function(result) {
_.each(result, function(item) {
var $item = $(QWeb.render("PetToy", {item: item}));
self.$el.append($item);
});
});
},
}); }

QWeb模板:

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

<templates xml:space="preserve">
<t t-name="HomePage">
<div class="oe_petstore_homepage">
<div class="oe_petstore_homepage_left"></div>
<div class="oe_petstore_homepage_right"></div>
</div>
</t>
<t t-name="MessageofTheDay">
<div class="oe_petstore_motd">
<p class="oe_mywidget_message_of_the_day"></p>
</div>
</t>
<t t-name="PetToysList">
<div class="oe_petstore_pettoyslist">
</div>
</t>
<t t-name="PetToy">
<div class="oe_petstore_pettoy">
<p><t t-esc="item.name"/></p>
<p><img t-att-src="'data:image/jpg;base64,'+item.image"/></p>
</div>
</t>
</templates>

CSS样式:

.oe_petstore_homepage {
display: table;
} .oe_petstore_homepage_left {
display: table-cell;
width : 300px;
} .oe_petstore_homepage_right {
display: table-cell;
width : 300px;
} .oe_petstore_motd {
margin: 5px;
padding: 5px;
border-radius: 3px;
background-color: #F0EEEE;
} .oe_petstore_pettoyslist {
padding: 5px;
} .oe_petstore_pettoy {
margin: 5px;
padding: 5px;
border-radius: 3px;
background-color: #F0EEEE;
}

OpenERP Web开发的更多相关文章

  1. OpenERP|odoo Web开发

    在OpenERP 7 和 Odoo 8下测试均可. 1.相关库/框架 主要:jQuery(使用1.8.3,如果使用新版本,其他jQuery插件也要升级或修改).Underscore.Qweb 其他:都 ...

  2. 为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?

    今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术框架由struts2迁移到springMVC,我突然有了一个新的疑 ...

  3. Go web开发初探

    2017年的第一篇博客,也是第一次写博客,写的不好,请各位见谅. 本人之前一直学习java.java web,最近开始学习Go语言,所以也想了解一下Go语言中web的开发方式以及运行机制. 在< ...

  4. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

  5. .NET Web开发技术简单整理

    在最初学习一些编程语言.一些编程技术的时候,做的更多的是如何使用该技术,如何更好的使用该技术解决问题,而没有去关注它的相关性.关注它的理论支持,这种学习技术的方式是短平快.其实工作中有时候也是这样,公 ...

  6. web 开发自动化grunt

    现在web开发自动化已很流行,如何进行压缩文件,如何进行测试js是否正确,如何进行 检测html文件是否规范等等都可以通过web自动化技术进行实现,只要打一个命令即可. 本文主要是通过grunt进行实 ...

  7. eclipse SE增加Web开发插件

    最近接触了些java项目,之前安装了eclipse SE版本.没有Web开发插件,调试不了Web代码.点击“Window”--“Preference” 左边菜单栏是找不到“Server”项来配置服务器 ...

  8. Web 开发中很实用的10个效果【附源码下载】

    在工作中,我们可能会用到各种交互效果.而这些效果在平常翻看文章的时候碰到很多,但是一时半会又想不起来在哪,所以养成知识整理的习惯是很有必要的.这篇文章给大家推荐10个在 Web 开发中很有用的效果,记 ...

  9. 12款简化 Web 开发的 JavaScript 开发框架

    前端框架简化了开发过程中,像 Bootstrap 和 Foundation 就是前端框架的佼佼者.在这篇文章了,我们编制了一组新鲜的,实用的,可以帮助您建立高质量的 Web 应用程序的 JavaScr ...

随机推荐

  1. ( VIJOS )VOJ 1049 送给圣诞夜的礼品 矩阵快速幂

    https://vijos.org/p/1049   非常普通的矩阵快速幂... 但是我 第一次写忘了矩阵不能交换律... 第一二次提交RE直到看到题解才发现这道题不能用递归快速幂... 第三次提交成 ...

  2. 【最小表示法】BZOJ1398-寻找朋友

    [题目大意] 判断两个字符串是否循环同构. [思路] 我一开始的做法是直接同时在两个字符串上求最小表示法,只有部分测试点能过,理由未知,以后再来思考. 现在做法:分别求出两个字符串的最小表示法,再比较 ...

  3. 【洛谷】P1052 过河【DP+路径压缩】

    P1052 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙 ...

  4. Ajax 跨域问题(JSONP && Access-Control-Allow-Origin)

    1.使用jsonp跨域请求 2.通过设置服务端头部跨域请求 3.设置nginx/apach 使用jsonp跨域请求 什么是Jsonp JSONP(JSON with Padding)是一个非官方的协议 ...

  5. Java获取Access数据库连接单例简单实例

    Java在连接Access数据库时比较方便,不用导入第三方的jar包,jdk中内置的odbc可以完成Access数据库的访问,需要注意的是,我们首先要配置Access数据库的数据源,还要区分x86和x ...

  6. Shell基础学习(三) 传递参数

    我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推…… 以下实例我们向脚本传递三个参数 ...

  7. 移动端 关于 键盘将input 框 顶上去的解决思路---个人见解

    在移动端,经常会遇到input获得焦点时候弹出的虚拟键盘将整体页面布局打乱的情况. 比如说是这种 输入框未获得焦点键盘未抬起的时候: 输入框获得焦点键盘抬起的时候 这种情况下,不管是上面的textar ...

  8. mysql知识点(三)

    1.表关联是可以利用两个表的索引的,如果是用子查询,至少第二次查询是没有办法使用索引的. 2.  为了给主查询提供数据而首先执行的查询被叫做子查询 3.如果WHERE子句的查询条件里使用了函数(WHE ...

  9. UML建模工具Visio 、Rational Rose、PowerDesign的比较

    UML建模工具Visio .Rational Rose.PowerDesign的比较   ROSE是直接从UML发展而诞生的设计工具,它的出现就是为了对UML建模的支持,ROSE一开始没有对数据库端建 ...

  10. 关于linux的进程中的各个线程cpu占用情况的分析和查看

    我们常常会在新开的服搭建一个游戏的server,有时候要进行压力測试,那么怎样来看呢,一般我们会通过top命令查看各个进程的cpu和内存占用情况,获得到了我们的进程id,然后我们或许会通过pstack ...