上一章咱們實現了一個原生的html例子,本章咱們將採用Extjs實現界面的展示,來講明MVC模式下咱們是怎麼考慮界面與業務層的關係的。javascript
首先,咱們在inventory app下增長一個static目錄,拷貝Extjs發佈目錄到static下,本章節例子咱們採用的是Extjs 4.1.1版本進行說明演示,Django項目可以訪問static目錄咱們須要修改項目setting.py的STATIC_ROOT項的值,項目才能正確裝載引用的靜態文件。css
… # Absolute path to the directory static files should be collected to. # Don't put anything in this directory yourself; store your static files # in apps' "static/" subdirectories and in STATICFILES_DIRS. # Example: "/home/media/media.lawrence.com/static/" import os.path STATIC_ROOT = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'static').replace('\\', '/')
咱們仿照上一章頁面結構實現Extjs查詢界面模板,模板代碼以下:html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> <link href="../static/ExtJs/resources/css/ext-all.css" rel="stylesheet" /> <script src="../static/ExtJs/bootstrap.js"></script> <script type="text/javascript"> Ext.onReady(function () { // var button1 = Ext.create('Ext.button.Button', { // text: 'search', // handler: function () { // myStore.load({ // params: { q: '螺母' } // }); // } // }); //定義Extjs端 model Ext.define('inventory', { extend: 'Ext.data.Model', fields: [ { name: 'InventoryId', type: 'string' }, { name: 'ItemName', type: 'string' }, { name: 'Amount', type: 'string' }, ] }); //申明一個Store類型的變量 var myStore = Ext.create('Ext.data.Store', { model: 'inventory', id: 'store1', proxy: { type: 'ajax', url: '/getInventoryByItemName/', //Store與後臺的交互url reader: { type: 'json', } } }); //定義查詢TextField和Button var textField1 = Ext.create('Ext.form.Panel', { width: '100%', renderTo: 'div0', layout: { type: 'hbox', // 子元素橫向佈局 padding: 5 }, items: [ { xtype: 'textfield', name: 'query', id: 'query', fieldLabel: 'Item Name:', }, { xtype:'button', text: 'search', handler: function () { myStore.load({ params: { q: Ext.getCmp("query").getValue() } //Store裝載數據是傳入查詢參數 }); } } ] }); var grid = Ext.create('Ext.grid.Panel', { title: '列表', store: myStore, id: 'grid1', columns: [ { text: 'id', dataIndex: 'InventoryId' }, { text: 'ItemName', dataIndex: 'ItemName' }, { text: 'Amount', dataIndex: 'Amount' } ], width: '100%', height: 500, forceFit: true, renderTo: 'div1', }); }); </script> </head> <body> <div id="div0"></div> <div id="div1"></div> </body> </html>
代碼說明:Extjs頁面咱們首先定義了一個界面使用的model類,界面控件包括文本框、按鈕、grid和store。Store裏咱們使用了一個重要的後臺交互url: / getInventoryByItemName,這個url以json格式字符串來返回查詢結果,最後,返回的結果集綁定到grid裏顯示,查詢按鈕的事件裏,咱們根據查詢條件返回的json從新裝載store,刷新grid顯示。關於Extjs更多的控件和用法,請參考Extjs管網,筆者在這裏更多的是說明思路。前端
接下里咱們在views裏面增長getInventoryByItemName函數以json返回數據集,併發布到urls.py裏。java
咱們在views.py裏增長函數getInventoryByItemName,請注意實現代碼裏,仍然是委託調用了biz層的getInventoryByItemName,這個函數的功能與原來的inventoryQuery基本功能是一致的,只是增長了Json格式化的代碼部分,同時直接返回Json字符串,而不是加載模板返回渲染的網頁,代碼以下:python
def getInventoryByItemName(request): error = False inventorysJson = '[]' if 'q' in request.GET: q = request.GET['q'] if not q: error = True elif len(q) > 20: error = True else: biz = InventoryBiz() inventorys =biz.getInventoryByItemName(q) inventorysJson=u'[' for inventory in inventorys: inventorysJson = inventorysJson + u'{"InventoryId":"' + str( inventory.InventoryId) + u'","ItemName":"' + inventory.Item.ItemName + u'","Amount":"' + str( inventory.Amount) + u'"}' inventorysJson = inventorysJson + u']' return HttpResponse(inventorysJson)
代碼重構的這個變化會致使系統的整個結構發生很大的變化,後面的章節咱們會逐步的講到。getInventoryByItemName url變成了一個返回Json格式查詢結果的url請求,成爲一個能夠供各類支持json格式客戶端調用的API,爲咱們的客戶端將來支持擴展到android、iOS和windows phone等前端展示提供了架構基礎。jquery
Views.py … def inventoryQueryExtjs(request): return render_to_response('inventoryQueryExtjs.html') urls.py … url(r'^inventoryQueryExtjs/$',views.inventoryQueryExtjs),
注意:與原生html不一樣,採用Extjs技術的頁面發佈了兩個url一個專門用來渲染頁面inventoryQueryExtjs,一個變成了專門的返回查詢結果的url請求:getInventoryByItemName,這個結構上的變化讓業務邏輯層與界面層,實現了進一步的解耦和,將來咱們能夠不斷的衍生界面端(客戶端),同時,全部客戶端調用統一的後臺服務。android
最後,訪問inventoryQueryExtjs頁面的結果以下圖:ajax
本小節咱們延伸一下頁面框架,用當下流行的頁面框架Bootsstrap實現上面的庫存查詢界面。django
http://getbootstrap.com/ 下載Bootstrap文件;
https://jquery.com/ 下載JQuery文件。
兩個文件解壓縮後分別拷貝粘貼到工程的static目錄下。
這裏爲了簡化數據加載,咱們還採用了一個第三方的bootstrap-table做爲table grid操做的控件,
http://wenzhixin.net.cn/p/bootstrap-table/docs/?locale=zh 咱們下載完整包後只拷貝bootstrap-table.css\bootstrap-table.js到static目錄下:
咱們新增的inventoryQueryBootstrap.html代碼以下:
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <link href="../static/bootstrap/css/bootstrap.min.css" rel="stylesheet" /> <script src="../static/JQuery/jquery-2.1.4.min.js"></script> <script src="../static/bootstrap/js/bootstrap.min.js"></script> <script src="../static/bootstrap/table/bootstrap-table.js"></script> </head> <body> <form class="form-inline" role="form"> <div class="form-group"> <label for="name">Item Name:</label> <input type="text" class="form-control" id="ItemName"placeholder="請輸入物料名稱"> <button id="search" type="button">search</button> </div> </form> <table id="inventorysTable" data-cache="false"> <thead> <tr> <th data-field="InventoryId">Id</th> <th data-field="ItemName">ItemName</th> <th data-field="Amount">Amount</th> </tr> </thead> </table> </body> </html> <script type="text/javascript"> //初始化用戶列表設置 $('#inventorysTable').bootstrapTable( { striped: true, sidePagination: "client", url: '/getInventoryByItemName/', }); //查詢按鈕點擊事件 $('#search').click(function () { var itemName = $('#ItemName').val(); $('#inventorysTable').bootstrapTable('refresh', { url: '/getInventoryByItemName/' + "?q=" + encodeURIComponent(itemName), }); }); </script>
注:上面代碼中的encodeURIComponent主要是解決IE瀏覽器的中文顯示亂碼問題。
頁面運行結果以下:
本章是筆者最想寫的章節,也是筆者多年開發經驗的一個心得,如何經過好的架構來知足和改進項目系統的架構最後獲得一個「低耦合,高內聚」的軟件架構,在這個一個結構基礎上咱們能夠不斷的改進和重構咱們的項目代碼,爲項目自己業務的進化打下堅實的基礎。將來筆者的其它文章會繼續引用這一服務來講明其它客戶端的開發。
好的系統架構確實會爲咱們項目的長期帶來收益,也可能會犧牲一點短時間效率,因此整個團隊的項目管理若是是創建在敏捷模式的基礎上,就會在必定範圍內減小對短時間效率的影響。咱們不用過分設計,以知足當前需求爲準,最快的實現功能,並有合理的粒度的單元測試。這樣,將來發現這樣的代碼結構不知足須要時,咱們經過重構來改進代碼,並經過單元測試迴歸來驗證代碼是否符合原先和如今的設計,最終讓項目造成一種能夠不斷進化的機制。
本章結束python的基本的開發模式就說明完了,咱們介紹在django工程裏何構如建MVC模式就告一段落了,下一章開始咱們講講項目的部署和發佈。