Python開發入門與實戰14-基於Extjs的界面


14. 基於Extjs的界面

上一章我們實現了一個原生的html例子,本章我們將采用Extjs實現界面的展現,來說明MVC模式下我們是怎么考慮界面與業務層的關系的。

14.1. 引用Extjs目錄

首先,我們在inventory app下增加一個static目錄,拷貝Extjs發布目錄到static下,本章節例子我們采用的是Extjs 4.1.1版本進行說明演示,Django項目能夠訪問static目錄我們需要修改項目setting.py的STATIC_ROOT項的值,項目才能正確裝載引用的靜態文件。

# 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('\\', '/')

14.2. 增加inventoryQueryExtjs.html模板文件

我們仿照上一章頁面結構實現Extjs查詢界面模板,模板代碼如下:

<!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里。

14.3. 數據交互url

我們在views.py里增加函數getInventoryByItemName,請注意實現代碼里,仍然是委托調用了biz層的getInventoryByItemName,這個函數的功能與原來的inventoryQuery基本功能是一致的,只是增加了Json格式化的代碼部分,同時直接返回Json字符串,而不是加載模板返回渲染的網頁,代碼如下:

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等前端展現提供了架構基礎。

1.4. 發布Extjs頁面

Views.py

…

def inventoryQueryExtjs(request):

    return render_to_response('inventoryQueryExtjs.html')

urls.py 

…

url(r'^inventoryQueryExtjs/$',views.inventoryQueryExtjs),

注意:與原生html不同,采用Extjs技術的頁面發布了兩個url一個專門用來渲染頁面inventoryQueryExtjs,一個變成了專門的返回查詢結果的url請求:getInventoryByItemName,這個結構上的變化讓業務邏輯層與界面層,實現了進一步的解耦和,未來我們可以不斷的衍生界面端(客戶端),同時,所有客戶端調用統一的后台服務。

最后,訪問inventoryQueryExtjs頁面的結果如下圖:

image

14.5. 采用流行的Bootstrap框架頁面

本小節我們延伸一下頁面框架,用當下流行的頁面框架Bootsstrap實現上面的庫存查詢界面。

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瀏覽器的中文顯示亂碼問題。

頁面運行結果如下:

image

14.6. 小結

本章是筆者最想寫的章節,也是筆者多年開發經驗的一個心得,如何通過好的架構來滿足和改進項目系統的架構最后得到一個“低耦合,高內聚”的軟件架構,在這個一個結構基礎上我們可以不斷的改進和重構我們的項目代碼,為項目本身業務的進化打下堅實的基礎。未來筆者的其它文章會繼續引用這一服務來說明其它客戶端的開發。

好的系統架構確實會為我們項目的長期帶來收益,也可能會犧牲一點短期效率,所以整個團隊的項目管理如果是建立在敏捷模式的基礎上,就會在一定范圍內減少對短期效率的影響。我們不用過度設計,以滿足當前需求為准,最快的實現功能,並有合理的粒度的單元測試。這樣,未來發現這樣的代碼結構不滿足需要時,我們通過重構來改進代碼,並通過單元測試回歸來驗證代碼是否符合原先和現在的設計,最終讓項目形成一種可以不斷進化的機制。

本章結束python的基本的開發模式就說明完了,我們介紹在django工程里何構如建MVC模式就告一段落了,下一章開始我們講講項目的部署和發布。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM