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]javascript

  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]css

  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]html

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


  3.類的定義
  從instance.web.Class基類擴展:
[javascript]java

  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]python

  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]web

  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.     width: 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;  
相關文章
相關標籤/搜索