• OpenERP|odoo Web开发


    在OpenERP 7 和 Odoo 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中通过:
    [python]

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

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

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

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

    1. http://localhost:8069/?debug  


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

    1. instance.oepetstore.MyClass = instance.web.Class.extend({  
    2.     say_hello: function() {  
    3.         console.log("hello");  
    4.     },  
    5. });  
    6. var my_object = new instance.oepetstore.MyClass();  
    7. my_object.say_hello();  

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

    1. instance.oepetstore.MyClass = instance.web.Class.extend({  
    2.     init: function(name) {  
    3.         this.name = name;  
    4.     },  
    5.     say_hello: function() {  
    6.         console.log("hello", this.name);  
    7.     },  
    8. });  
    9.   
    10. var my_object = new instance.oepetstore.MyClass("Nicolas");  
    11. my_object.say_hello();  

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

    1. instance.oepetstore.MySpanishClass = instance.oepetstore.MyClass.extend({  
    2.     say_hello: function() {  
    3.         this._super();  
    4.         console.log("translation in Spanish: hola", this.name);  
    5.     },  
    6. });  
    7.   
    8. var my_object = new instance.oepetstore.MySpanishClass("Nicolas");  
    9. my_object.say_hello();  


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

    1. this.$el.append("
      Hello dear OpenERP user!
      ");  

      往部件中添加一个

    块及内容。
      部件中可以插入其他部件进行组合:
    [javascript]
    1. instance.oepetstore.GreetingsWidget = instance.web.Widget.extend({  
    2.     start: function() {  
    3.         this.$el.addClass("oe_petstore_greetings");  
    4.         this.$el.append("
      We are so happy to see you again in this menu!
      ");  
    5.     },  
    6. });  
    7. instance.oepetstore.HomePage = instance.web.Widget.extend({  
    8.     start: function() {  
    9.         this.$el.addClass("oe_petstore_homepage");  
    10.         this.$el.append("
      Hello dear OpenERP user!
      ");  
    11.         var greeting = new instance.oepetstore.GreetingsWidget(this); // 创建部件的时候传入父部件的实例作为构造参数。  
    12.         greeting.appendTo(this.$el);  
    13.     },  
    14. });  
      父子部件可以通过getChildren()、getParent()进行互相访问。如果重载部件的构造函数,第一个参数必须是父部件,并且必须传递给基类。
    [javascript]
    1. instance.oepetstore.GreetingsWidget = instance.web.Widget.extend({  
    2.     init: function(parent, name) {  
    3.         this._super(parent);  
    4.         this.name = name;  
    5.     },  
    6. });  
      如果作为顶层部件创建,parent参数应该是null。
      部件实例可以调用destroy()方法销毁。

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

      

      •       
      •   
      •   定义一个名为“HomePageTemplate”的模板。
          使用方法1:
        [javascript]
        1. instance.oepetstore.HomePage = instance.web.Widget.extend({  
        2.     start: function() {  
        3.         this.$el.append(QWeb.render("HomePageTemplate"));  
        4.     },  
        5. });  
          使用方法2:
        [javascript]
        1. instance.oepetstore.HomePage = instance.web.Widget.extend({  
        2.     template: "HomePageTemplate",  
        3.     start: function() {  
        4.         ...  
        5.     },  
        6. });  
          模板里面的条件控制t-if:
        [html]
        1.   
        2.     true is true  
        3.   
        4.   
        5.     true is not true  
        6.   
          枚举t-foreach和t-as:
        [html]
        1.   
        2.     
            
        3.         Hello   
        4.       
        5.   
          属性赋值,在属性名前加前缀“t-att-”:
        [html]
        1.   
          将input控件的value属性赋值为“defaultName”。
          部件开发示例,显示产品列表。
          JavaScript脚本:
        [javascript]
        1. openerp.oepetstore = function(instance) {  
        2.     var _t = instance.web._t,  
        3.         _lt = instance.web._lt;  
        4.     var QWeb = instance.web.qweb;  
        5.   
        6.     instance.oepetstore = {};  
        7.   
        8.     instance.oepetstore.HomePage = instance.web.Widget.extend({  
        9.         start: function() {  
        10.             var products = new instance.oepetstore.ProductsWidget(this, ["cpu", "mouse", "keyboard", "graphic card", "screen"], "#00FF00");  
        11.             products.appendTo(this.$el);  
        12.         },  
        13.     });  
        14.   
        15.     instance.oepetstore.ProductsWidget = instance.web.Widget.extend({  
        16.         template: "ProductsWidget",  
        17.         init: function(parent, products, color) {  
        18.             this._super(parent);  
        19.             this.products = products;  
        20.             this.color = color;  
        21.         },  
        22.     });  
        23.   
        24.     instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');  
        25. }  
          QWeb模板:
        [html]
        1.   
        2.   
        3.   
        4.       
        5.         
            
        6.               
        7.                 
            
        8.               
        9.           
        10.       
        11.   
          CSS样式:
        [css]
        1. .oe_products_item {  
        2.     display: inline-block;  
        3.     padding: 3px;  
        4.     margin: 5px;  
        5.     border: 1px solid black;  
        6.     border-radius: 3px;  
        7. }  


          6.部件事件与特性
        [javascript]
        1. instance.oepetstore.ConfirmWidget = instance.web.Widget.extend({  
        2.     start: function() {  
        3.         var self = this;  
        4.         this.$el.append("
          Are you sure you want to perform this action?
          " +  
        5.             "<button class='ok_button'>Ok" +  
        6.             "<button class='cancel_button'>Cancel");  
        7.         this.$el.find("button.ok_button").click(function() { // 在按钮上绑定click事件  
        8.             self.trigger("user_choose", true); // 触发自定义user_choose事件,传递事件参数true/false  
        9.         });  
        10.         this.$el.find("button.cancel_button").click(function() {  
        11.             self.trigger("user_choose", false);  
        12.         });  
        13.     },  
        14. });  
        15.   
        16. instance.oepetstore.HomePage = instance.web.Widget.extend({  
        17.     start: function() {  
        18.         var widget = new instance.oepetstore.ConfirmWidget(this);  
        19.         widget.on("user_choose", this, this.user_choose); // 在部件上绑定user_choose事件到响应函数user_choose  
        20.         widget.appendTo(this.$el);  
        21.     },  
        22.     user_choose: function(confirm) {  
        23.         if (confirm) {  
        24.             console.log("The user agreed to continue");  
        25.         } else {  
        26.             console.log("The user refused to continue");  
        27.         }  
        28.     },  
        29. });  
          部件特性(Properties)的使用:
        [javascript]
        1. this.widget.on("change:name", this, this.name_changed); //绑定name特性的change事件  
        2. this.widget.set("name", "Nicolas"); // 设置特性值  
        3. var getedname = this.widget.get("name"); // 读取特性值  


          7.部件访问  简化jQuery选择器:
        [javascript]
        1. this.$el.find("input.my_input")  
          等于
        [javascript]
        1. this.$("input.my_input")  
          因此事件的绑定:
        [javascript]
        1. this.$el.find("input").change(function() {  
        2.                 self.input_changed();  
        3.             });  
          可以简化为:
        [javascript]
        1. this.$(".my_button").click(function() {  
        2.             self.button_clicked();  
        3.         });  
          进一步,可以通过部件提供的events字典属性简化为:
        [javascript]
        1. instance.oepetstore.MyWidget = instance.web.Widget.extend({  
        2.     events: {  
        3.         "click .my_button": "button_clicked",  
        4.     },  
        5.     button_clicked: function() {  
        6.         ..  
        7.     }  
        8. });  
          注意:这种方法只是绑定jQuery提供的DOM事件机制,不能用于部件的on语法绑定部件自身的事件。  event属性的键名由两部分组成:事件名称和jQuery选择器,用空格分开。属性值是响应事件的函数(方法)。
          事件使用示例:
          JavaScript脚本:
        [javascript]
        1. openerp.oepetstore = function(instance) {  
        2.     var _t = instance.web._t,  
        3.         _lt = instance.web._lt;  
        4.     var QWeb = instance.web.qweb;  
        5.   
        6.     instance.oepetstore = {};  
        7.   
        8.     instance.oepetstore.ColorInputWidget = instance.web.Widget.extend({  
        9.         template: "ColorInputWidget",  
        10.         start: function() {  
        11.             var self = this;  
        12.             this.$el.find("input").change(function() {  
        13.                 self.input_changed();  
        14.             });  
        15.             self.input_changed();  
        16.         },  
        17.         input_changed: function() {  
        18.             var color = "#";  
        19.             color += this.$el.find(".oe_color_red").val();  
        20.             color += this.$el.find(".oe_color_green").val();  
        21.             color += this.$el.find(".oe_color_blue").val();  
        22.             this.set("color", color);  
        23.         },  
        24.     });  
        25.   
        26.     instance.oepetstore.HomePage = instance.web.Widget.extend({  
        27.         template: "HomePage",  
        28.         start: function() {  
        29.             this.colorInput = new instance.oepetstore.ColorInputWidget(this);  
        30.             this.colorInput.on("change:color", this, this.color_changed);  
        31.             this.colorInput.appendTo(this.$el);  
        32.         },  
        33.         color_changed: function() {  
        34.             this.$el.find(".oe_color_div").css("background-color", this.colorInput.get("color"));  
        35.         },  
        36.     });  
        37.   
        38.     instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');  
        39. }  
          QWeb模板:
        [html]
        1.   
        2.   
        3.   
        4.       
        5.         
            
        6.             Red: <br >  
        7.             Green: <br >  
        8.             Blue: <br >  
        9.           
        10.       
        11.       
        12.         
            
        13.               
        14.           
        15.       
        16.   
          CSS样式:
        [css]
        1. .oe_color_div {  
        2.      100px;  
        3.     height: 100px;  
        4.     margin: 10px;  
        5. }  


          8.修改已有的部件和类
          可以用include()方法重载已有的部件和类,这个和继承机制类似,是一种插入的方法:
        [javascript]
        1. var TestClass = instance.web.Class.extend({  
        2.     testMethod: function() {  
        3.         return "hello";  
        4.     },  
        5. });  
        6.   
        7. TestClass.include({  
        8.     testMethod: function() {  
        9.         return this._super() + " world";  
        10.     },  
        11. });  
        12.   
        13. console.log(new TestClass().testMethod());  
        14. // will print "hello world"  
          应尽量避免使用这种机制导致的复杂性。

          9.与服务器的交互-读取数据模型
          客户端使用Ajax与服务器交互,不过OpenERP框架提供了简化的方法,通过数据模型进行访问。
          OpenERP自动将服务端的数据模型转化为客户端端模型,直接调用即可。服务器上petstore.py里面的模型:
        [python]
        1. class message_of_the_day(osv.osv):  
        2.     _name = "message_of_the_day"  
        3.   
        4.     def my_method(self, cr, uid, context=None):  
        5.         return {"hello": "world"}  
        6.   
        7.     _columns = {  
        8.         'message': fields.text(string="Message"),  
        9.         'color': fields.char(string="Color", size=20),  
        10.     }  
          客户端调用例子:
        [javascript]
        1. instance.oepetstore.HomePage = instance.web.Widget.extend({  
        2.     start: function() {  
        3.         var self = this;  
        4.         var model = new instance.web.Model("message_of_the_day");  
        5.         model.call("my_method", [], {context: new instance.web.CompoundContext()}).then(function(result) {  
        6.             self.$el.append("
          Hello " + result["hello"] + "
          ");  
        7.             // will show "Hello world" to the user  
        8.         });  
        9.     },  
        10. });  

          模型的call()方法参数:
            第一个参数name是方法的名称;
            第二个参数args是按照顺序排列的参数数组。OpenERP定义的模型方法前三个参数(self, cr, uid)是固定的,由框架产生,也就是说传递的参数数组从第四个开始插入。而context又是特殊的。例子:
            方法定义:
        [python]
        1. def my_method2(self, cr, uid, a, b, c, context=None):  
          调用:
        [javascript]
        1. model.call("my_method", [1, 2, 3], ...// with this a=1, b=2 and c=3  

            第三个参数kwargs为命名参数,按照名称传递给Python的方法参数。例如:
        [javascript]
        1. 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]
        1. 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]
        1. 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]
        1. openerp.oepetstore = function(instance) {  
        2.     var _t = instance.web._t,  
        3.         _lt = instance.web._lt;  
        4.     var QWeb = instance.web.qweb;  
        5.   
        6.     instance.oepetstore = {};  
        7.   
        8.     instance.oepetstore.HomePage = instance.web.Widget.extend({  
        9.         template: "HomePage",  
        10.         start: function() {  
        11.             var motd = new instance.oepetstore.MessageOfTheDay(this);  
        12.             motd.appendTo(this.$el);  
        13.         },  
        14.     });  
        15.   
        16.     instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');  
        17.   
        18.     instance.oepetstore.MessageOfTheDay = instance.web.Widget.extend({  
        19.         template: "MessageofTheDay",  
        20.         init: function() {  
        21.             this._super.apply(this, arguments);  
        22.         },  
        23.         start: function() {  
        24.             var self = this;  
        25.             new instance.web.Model("message_of_the_day").query(["message"]).first().then(function(result) {  
        26.                 self.$(".oe_mywidget_message_of_the_day").text(result.message);  
        27.             });  
        28.         },  
        29.     });  
        30.   
        31. }  
          QWeb模板:
        [html]
        1.   
        2.   
        3.   
        4.       
        5.           
        6.           
        7.       
        8.       
        9.           
        10.                
        11.           
        12.       
        13.   
          CSS样式:
        [css]
        1. .oe_petstore_motd {  
        2.     margin: 5px;  
        3.     padding: 5px;  
        4.     border-radius: 3px;  
        5.     background-color: #F0EEEE;  
        6. }  

          示例2:组合显示每日提示和产品列表
          服务器端从OpenERP的产品表继承一个类(模型):
        [python]
        1. class product(osv.osv):  
        2.        _inherit = "product.product"  
        3.     
        4.        _columns = {  
        5.            'max_quantity': fields.float(string="Max Quantity"),  
        6.        }  
          因此数据是保存在product.product表中的,只是扩充了一个“max_quantity”字段;这个例子结合前面的每日提示信息,显示二列,左面一列显示产品列表,右面显示提示信息。
          JavaScript脚本:
        [javascript]
        1. openerp.oepetstore = function(instance) {  
        2.     var _t = instance.web._t,  
        3.         _lt = instance.web._lt;  
        4.     var QWeb = instance.web.qweb;  
        5.   
        6.     instance.oepetstore = {};  
        7.   
        8.     instance.oepetstore.HomePage = instance.web.Widget.extend({  
        9.         template: "HomePage",  
        10.         start: function() {  
        11.             var pettoys = new instance.oepetstore.PetToysList(this);  
        12.             pettoys.appendTo(this.$(".oe_petstore_homepage_left"));  
        13.             var motd = new instance.oepetstore.MessageOfTheDay(this);  
        14.             motd.appendTo(this.$(".oe_petstore_homepage_right"));  
        15.         },  
        16.     });  
        17.   
        18.     instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');  
        19.   
        20.     instance.oepetstore.MessageOfTheDay = instance.web.Widget.extend({  
        21.         template: "MessageofTheDay",  
        22.         init: function() {  
        23.             this._super.apply(this, arguments);  
        24.         },  
        25.         start: function() {  
        26.             var self = this;  
        27.             new instance.web.Model("message_of_the_day").query(["message"]).first().then(function(result) {  
        28.                 self.$(".oe_mywidget_message_of_the_day").text(result.message);  
        29.             });  
        30.         },  
        31.     });  
        32.   
        33.     instance.oepetstore.PetToysList = instance.web.Widget.extend({  
        34.         template: "PetToysList",  
        35.         start: function() {  
        36.             var self = this;  
        37.             new instance.web.Model("product.product").query(["name", "image"])  
        38.                 .filter([["categ_id.name", "=", "Pet Toys"]]).limit(5).all().then(function(result) {  
        39.                 _.each(result, function(item) {  
        40.                     var $item = $(QWeb.render("PetToy", {item: item}));  
        41.                     self.$el.append($item);  
        42.                 });  
        43.             });  
        44.         },  
        45.     });  
        46.   
        47. }  
          QWeb模板:
        [html]
        1.   
        2.   
        3.   
        4.       
        5.           
        6.               
        7.               
        8.           
        9.       
        10.       
        11.           
        12.                
        13.           
        14.       
        15.       
        16.           
        17.           
        18.       
        19.       
        20.           
        21.                
        22.             

          <img t-att- src="'data:image/jpg;base64,'+item.image">

            
        23.           
        24.       
        25.   
          CSS样式:
        [css]
        1. .oe_petstore_homepage {  
        2.     display: table;  
        3. }  
        4.   
        5. .oe_petstore_homepage_left {  
        6.     display: table-cell;  
        7.     width : 300px;  
        8. }  
        9.   
        10. .oe_petstore_homepage_right {  
        11.     display: table-cell;  
        12.     width : 300px;  
        13. }  
        14.   
        15. .oe_petstore_motd {  
        16.     margin: 5px;  
        17.     padding: 5px;  
        18.     border-radius: 3px;  
        19.     background-color: #F0EEEE;  
        20. }  
        21.   
        22. .oe_petstore_pettoyslist {  
        23.     padding: 5px;  
        24. }  
        25.   
        26. .oe_petstore_pettoy {  
        27.     margin: 5px;  
        28.     padding: 5px;  
        29.     border-radius: 3px;  
        30.     background-color: #F0EEEE;  
  • 相关阅读:
    Pycharm中导入Python包的方法
    关于SOA架构设计的案例分析
    浅谈12306核心模型设计思路和架构设计
    美图数据统计分析平台架构演进
    有赞搜索系统的架构演进
    美团云的网络架构演进之路
    数据蜂巢架构演进之路
    1号店电商峰值与流式计算
    京东B2B业务架构演变
    饿了么:业务井喷时订单系统架构的演进
  • 原文地址:https://www.cnblogs.com/jacker1979/p/4784093.html
Copyright © 2020-2023  润新知