zoukankan      html  css  js  c++  java
  • OpenERP Web开发

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

    在7和8下测试均可。

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

      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 {
         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;
    }
    
  • 相关阅读:
    Java I/O基础
    Python基础篇(九)
    Python基础篇(八)
    thinkphp5中Indirect modification of overloaded element of XXX has no effect的解决办法
    关于json_encode转义斜杠的问题
    [thinkexceptionErrorException] glob() has been disabled for security reasons
    CentOS7 安装svn
    -bash: /usr/bin/yum: /usr/bin/python: bad interpreter: No such file or directory
    php在线编辑本地文件方法共享
    python一些不错的东西
  • 原文地址:https://www.cnblogs.com/chjbbs/p/3871151.html
Copyright © 2011-2022 走看看