OpenERP|odoo Web开发
在OpenERP 7 和 Odoo 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中通过:
[python]
- 'js': ['static/src/js/*.js'],
- 'css': ['static/src/css/*.css'],
- 'qweb': ['static/src/xml/*.xml'],
将所有js/css/xml(QWeb模板)文件包含进来。
oepetstore/static/js/petstore.js注释说明:
[javascript]
- 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”参数使脚本不压缩以便于调试,例如:
[javascript]
- http://localhost:8069/?debug
3.类的定义
从instance.web.Class基类扩展:
[javascript]
- 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访问对象实例的属性或方法:
[javascript]
- 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()调用基类被覆盖的方法。
[javascript]
- 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方法,例如:
[javascript]
- this.$el.append("
Hello dear OpenERP user!
");
往部件中添加一个
部件中可以插入其他部件进行组合:
[javascript]
- instance.oepetstore.GreetingsWidget = instance.web.Widget.extend({
- start: function() {
- this.$el.addClass("oe_petstore_greetings");
- this.$el.append("
We are so happy to see you again in this menu!
");
- },
- });
- instance.oepetstore.HomePage = instance.web.Widget.extend({
- start: function() {
- this.$el.addClass("oe_petstore_homepage");
- this.$el.append("
Hello dear OpenERP user!
");
- var greeting = new instance.oepetstore.GreetingsWidget(this); // 创建部件的时候传入父部件的实例作为构造参数。
- greeting.appendTo(this.$el);
- },
- });
父子部件可以通过getChildren()、getParent()进行互相访问。如果重载部件的构造函数,第一个参数必须是父部件,并且必须传递给基类。
[javascript]
- 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:
[html]
- Hello
- 定义一个名为“HomePageTemplate”的模板。
使用方法1:
[javascript]- instance.oepetstore.HomePage = instance.web.Widget.extend({
- start: function() {
- this.$el.append(QWeb.render("HomePageTemplate"));
- },
- });
使用方法2:
[javascript]- instance.oepetstore.HomePage = instance.web.Widget.extend({
- template: "HomePageTemplate",
- start: function() {
- ...
- },
- });
模板里面的条件控制t-if:
[html]- true is true
- true is not true
枚举t-foreach和t-as:
[html]- Hello
属性赋值,在属性名前加前缀“t-att-”:
[html]
将input控件的value属性赋值为“defaultName”。
部件开发示例,显示产品列表。
JavaScript脚本:
[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模板:
[html]CSS样式:
[css]- .oe_products_item {
- display: inline-block;
- padding: 3px;
- margin: 5px;
- border: 1px solid black;
- border-radius: 3px;
- }
6.部件事件与特性
[javascript]- instance.oepetstore.ConfirmWidget = instance.web.Widget.extend({
- start: function() {
- var self = this;
- this.$el.append("
Are you sure you want to perform this action?
" +
- "<button class='ok_button'>Ok" +
- "<button class='cancel_button'>Cancel");
- 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)的使用:
[javascript]- this.widget.on("change:name", this, this.name_changed); //绑定name特性的change事件
- this.widget.set("name", "Nicolas"); // 设置特性值
- var getedname = this.widget.get("name"); // 读取特性值
7.部件访问 简化jQuery选择器:
[javascript]- this.$el.find("input.my_input")
等于
[javascript]- this.$("input.my_input")
因此事件的绑定:
[javascript]- this.$el.find("input").change(function() {
- self.input_changed();
- });
可以简化为:
[javascript]- this.$(".my_button").click(function() {
- self.button_clicked();
- });
进一步,可以通过部件提供的events字典属性简化为:
[javascript]- instance.oepetstore.MyWidget = instance.web.Widget.extend({
- events: {
- "click .my_button": "button_clicked",
- },
- button_clicked: function() {
- ..
- }
- });
注意:这种方法只是绑定jQuery提供的DOM事件机制,不能用于部件的on语法绑定部件自身的事件。 event属性的键名由两部分组成:事件名称和jQuery选择器,用空格分开。属性值是响应事件的函数(方法)。
事件使用示例:
JavaScript脚本:
[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模板:
[html]- Red: <br >
- Green: <br >
- Blue: <br >
CSS样式:
[css]- .oe_color_div {
- width: 100px;
- height: 100px;
- margin: 10px;
- }
8.修改已有的部件和类
可以用include()方法重载已有的部件和类,这个和继承机制类似,是一种插入的方法:
[javascript]- 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里面的模型:
[python]- 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),
- }
客户端调用例子:
[javascript]- 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("
Hello " + result["hello"] + "
");
- // will show "Hello world" to the user
- });
- },
- });
模型的call()方法参数:
第一个参数name是方法的名称;
第二个参数args是按照顺序排列的参数数组。OpenERP定义的模型方法前三个参数(self, cr, uid)是固定的,由框架产生,也就是说传递的参数数组从第四个开始插入。而context又是特殊的。例子:
方法定义:
[python]- def my_method2(self, cr, uid, a, b, c, context=None):
调用:
[javascript]- model.call("my_method", [1, 2, 3], ...// with this a=1, b=2 and c=3
第三个参数kwargs为命名参数,按照名称传递给Python的方法参数。例如:
[javascript]- 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类提供用户的语言和时区信息。也可以在构造函数中添加另外的数据:
[javascript]- 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()方法,使用例子:
[javascript]- 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脚本:
[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模板:
[html]CSS样式:
[css]- .oe_petstore_motd {
- margin: 5px;
- padding: 5px;
- border-radius: 3px;
- background-color: #F0EEEE;
- }
示例2:组合显示每日提示和产品列表
服务器端从OpenERP的产品表继承一个类(模型):
[python]- class product(osv.osv):
- _inherit = "product.product"
- _columns = {
- 'max_quantity': fields.float(string="Max Quantity"),
- }
因此数据是保存在product.product表中的,只是扩充了一个“max_quantity”字段;这个例子结合前面的每日提示信息,显示二列,左面一列显示产品列表,右面显示提示信息。
JavaScript脚本:
[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模板:
[html]<img t-att- src="'data:image/jpg;base64,'+item.image">
CSS样式:
[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|odoo Web开发的更多相关文章
- OpenERP(odoo)开发实例之搜索检索过去3个月的数据
转自:http://www.chinamaker.net/ OpenERP(odoo)开发实例之搜索过滤:检索过去3个月的数据 解决这个问题的重点在于 relativedelta 的应用 示例代码如下 ...
- Odoo Web Service API
来自 Odoo Web服务暴露出相关的服务,路由分别是 /xmlrpc/ /xmlrpc/2/ /jsonrpc 根据 services 调用 后端对应服务的 方法method [定义 openerp ...
- 免费下载获取Odoo中文开发 指南 手册
引言 Odoo是一个强大的商业应用开源平台.在此基础上,构建了一套紧密集成的应用程序,涵盖了从CRM到销售到股票和会计的所有业务领域.Odoo有一个动态和不断增长的社区,不断增加功能.连接器和其他商业 ...
- 第十二章 Odoo 12开发之报表和服务端 QWeb
报表是业务应用非常有价值的功能,内置的 QWeb 引擎是报表的默认引擎.使用 QWeb 模板设计的报表可生成 HTML 文件并被转化成 PDF.也就是说我们可以很便捷地利用已学习的 QWeb 知识,应 ...
- 第十一章 Odoo 12开发之看板视图和用户端 QWeb
QWeb 是 Odoo 使用的模板引擎,它基于 XML 来生成 HTML 片断和页面.通过 QWeb可生成内容丰富的看板(Kankan)视图.报表和 CMS 网页.本文中我们将学习QWeb 语法以及如 ...
- 第十章 Odoo 12开发之后台视图 - 设计用户界面
本文将学习如何为用户创建图形化界面来与图书应用交互.我们将了解不同视图类型和小组件(widgets)之间的差别,以及如何使用它们来提供更优的用户体验. 本文主要内容有: 菜单项 窗口操作(Window ...
- 第五章 Odoo 12开发之导入、导出以及模块数据
大多数Odoo 模块的定义,如用户界面和安全规则,实际是存储在对应数据表中的数据记录.模块中的 XML 和 CSV 文件不是 Odoo 应用运行时使用,而是载入数据表的手段.正是因为这个原因,Odoo ...
- 第四章 Odoo 12 开发之模块继承
Odoo 的一个强大功能是无需直接修改底层对象就可以添加功能.这是通过其继承机制来实现的,采取在已有对象之上修改层来完成.这种修改可以在不同层上进行-模型层.视图层和业务逻辑层.我们创建新的模块来做出 ...
- 第三章 Odoo 12 开发之创建第一个 Odoo 应用
Odoo 开发通常都需要创建自己的插件模块.本文中我们将通过创建第一个应用来一步步学习如何在 Odoo 中开启和安装这个插件.我们将从基础的开发流学起,即创建和安装新插件,然后在开发迭代中更新代码来进 ...
随机推荐
- mouseover与mouseenter,mouseout与mouseleave的区别
mouseover与mouseenter 不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件.只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件. mouseout ...
- [实战]MVC5+EF6+MySql企业网盘实战(5)——ajax方式注册
写在前面 今天贴合到实际的客户需求仔细的想了下,其实在userInfo这个类里面很多字段都不是必须的.有很多的事业单位根本就不能上网,填写的邮箱也是exchange的,个人的详细信息都在ad里面可以取 ...
- LR-事务
一.对事务的理解 在LR中什么是事务,事务是记录从客户端到服务器端,服务器端返回到客户端应答的时间,可以反映出一个操作所用的时间.那么事务的时间主要是由响应时间.事务自身时间.浪费时间(wasted ...
- Recursion in Java
Recursion in Java 递归无出口 public class RecursionExample1 { public static void p() { System.out.println ...
- Java经典设计模式之五大创建型模式
转载: Java经典设计模式之五大创建型模式 一.概况 总体来说设计模式分为三大类: (1)创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. (2)结构型模式,共七种: ...
- 【JAVAWEB学习笔记】11_XML
今日内容介绍 编写服务器软件,访问指定配置内容 访问tomcat下已经发布的web项目 今日内容学习目标 可以编写xml存放任意内容 通过DTD约束编写指定格式的XML 通过Schema约束编写指定格 ...
- Linux命令之gdisk
gdisk -l [设备] gdisk又叫GPT fdisk,算是fdisk的延伸吧,主要使用的是GPT分区类型,用来划分容量大于2T的硬盘. 扩展1:分区类型GPT和MBR.GPT最大支持18EB( ...
- 导航控制器(UINavigationController)
导航控制器管理一系列显示层次型信息的场景.它创建一个视图管理器"栈",栈底为根视图控制器,用户在场景间切换时,依次将试图控制器压入栈中,且当前场景的试图控制器位于栈顶.要返回上一级 ...
- [转载]C++内存管理
[导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...
- CodeM资格赛5
早上起床太晚,最后没时间了.. 不是ac代码,下次题目在oj上线的时候再去做一下.. #include<iostream> #include<cstdio> #include& ...