# Python 學習筆記 : Django 2 測試 (一) : 請求與回應處理
# Python 學習筆記 : Django 2 測試 (二) : 模板基礎與靜態檔案
本篇測試參考了下面幾本書中的範例加以改寫 :
- It's django - 用 Python 迅速打造 Web 應用 (楊孟穎, 袁克倫, 碁峰)
- Python 新手使用 django 架站的 16 堂課 (何敏煌, 博碩)
- Python 新手使用 django 架站技術實作 (何敏煌, 林亮昀, 博碩)
- Python 網頁程式交易 App 實作 (林萍珍, 博碩)
- Beginning Django (Daniel Rubio, Apress)
- Django 2 Web Development Cookbook 3rd Edition(Jake Kronika, Packt)
- 一次搞定所有 Python Web 框架開發百科全書 (佳魁, 劉長龍)
- 科班出身的MVC網頁開發 : 使用Python + Django (佳魁, 王友釗)
# The Complete Guide To Install Django And Configure It
# 2019 iT 邦幫忙鐵人賽 : From Django 1.11 to Django 2.1 系列
# Django 2 By Example 全书翻译、踩坑及教程
Django 2 官方教學文件參考 :
# https://docs.djangoproject.com/en/2.2/
除了在上一篇中提到的 if-elif-else, for, 以及 empty 標籤外, Django 的預設模板引擎還提供了 include (匯入) 與 extend (繼承) 這兩個好用的標籤, 可將模板網頁結構化與模組化, 將相似性高的部分獨立拆開以便網頁可重複使用.
一. 匯入 (include) 模板網頁 :
在模板網頁中可用 include 標籤匯入其他網頁檔案, 檔名需以引號括起來 :
{% include "other_template.htm" %}
例如下列的 Hello World 網頁 :
<!--index.htm-->
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
<meta charset="utf-8">
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
可將 Hello World 網頁的內容部分單獨寫成 helloworld.htm 如下 :
<!--helloworld.htm-->
<h1>Hello World</h1>
然後再用 include 將其匯入 :
<!--index.htm-->
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
<meta charset="utf-8">
</head>
<body>
{% include "helloworld.htm" %}
</body>
</html>
可見使用 include 之前須對原網頁進行切割, 導致每個網頁 "片段" 檔案可能不是完整網頁而顯得很奇怪, 在網頁結構上將非常混亂. 模板網頁模組化主要還是靠繼承 (extend).
二. 繼承 (extends) 模板網頁 :
Django 預設的模板語言提供 extends 標籤可以繼承另一個模板網頁, 概念與物件導向中物件的繼承類似. 繼承 (extends) 與匯入 (include) 同樣是讀入另一個模板網頁檔案到目前檔案中, 但不同之處是 :
- 被繼承的模板都是完整的網頁, 而不是網頁片段. 被繼承的父模板網頁中定義了若干區塊 (block), 然後在子模板網頁中用具體的網頁填入父模板的指定區塊中.
- 繼承標籤 extend 必須放在網頁的最前面, 而匯入 include 則是網頁中任何地方皆可.
{% block block_name %}{% endblock %}
子模板會以具體的網頁片段填入 block 與 endblock 之間.
在子模板中繼承父模板時要放在第一行, 父模板檔名需用引號括起來 :
{% extends "father_template.htm" %}
然後就可以在子模板中以具體的網頁片段填入指定的區塊中 :
{% block block_name %} 網頁片段 {% endblock %}
例如上面的 Hello World 網頁, 可以先寫一個基礎模板網頁 base.htm 如下 :
<!--base.htm-->
<!DOCTYPE html>
<html>
<head>
<title>Base template</title>
<meta charset="utf-8">
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
然後就可以在子模板 index.htm 中繼承 base.htm, 然後用 block 標籤把網頁片段填入名為 content 的區塊中 :
<!--index.htm-->
{% extends 'base.htm' %}
{% block content %}
<h1>Hello World</h1>
{% endblock %}
上面為模板繼承的基本用法, 如果要在專案中使用各種前端框架, 有必要建立一個可共用, 更完整的 HTML5 基礎模板, 這裡面需包含 link, script, style 以及網頁內容等區塊, 如下所示 :
<!--base.htm-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{% block title %}{% endblock %}</title>
{% block link %}{% endblock %}
{% block script %}{% endblock %}
<style>
{% block style %}{% endblock %}
</style>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
注意, 此模板網頁標頭中以 style 標籤設定的樣式在子模板中直接書寫樣式內容即可, 不需要 style 標籤. 有了上面這個完整基礎模板, 就可以繼承它來製作前端框架專案的模板了.
有了 HTML5 的基礎模板 base.htm, 子模板就可以繼承它來建立專案網頁, 並以具體的網頁元素來填入父模板的區塊中 :
{% extends "base.htm" %}
{% block link %}
link 元素群 (樣式檔)
{% endblock %}
{% block script %}
script 元素群 (程式檔)
{% endblock %}
{% block body %}
網頁內容 + script 元素群
{% endblock %}
注意, 網頁內容區塊不一定要在子模板中填入, 可以在孫模板中再填入, 例如我們可以繼承基礎模板 (父模板) 建立各種前端框架模板 (子模板), 然後再於繼承這些框架專案模板的應用網頁模板 (孫模板) 中填入 body 區塊.
base.htm (父模板)
|____ jqueryui.htm (子模板)
| |____ jqapp.htm (孫模板)
|____ easyui.htm (子模板)
| |____ ezuiapp.htm (孫模板)
|____ bootstrap.htm (子模板)
|____ bsapp.htm (孫模板)
三. 框架專案模板 :
由於提供 UI 元件的前端框架通常需要許多圖檔與樣式檔, 如果要在專案中自備的話就必須下載後放在 static 子目錄下, 不僅麻煩還占用伺服器硬碟空間, 因此以下的框架專案模板都採用 CDN 供檔的方式取得資源.
1. jQuery UI 專案模板 :
jQueryUI 是以 jQuery 為基礎的網頁框架, 因此使用 jQuery UI 也必須匯入 jQuery 才行. jQuery UI 提供了許多好用的 UI 元件, 基本上足敷一般網頁專案之用, 另外有許多第三方函式庫可擴充 jQuery UI 的功能, 例如 DataTables 資料表格元件, 參考 :
# https://datatables.net/
配置 jQuery UI 執行環境可從官網下載自備, 亦可使用 CDN 資源, 參考 :
# jQuery UI 執行環境配置
# 如何在 GAE 上佈署 jQuery 與 ExtJS 專案
常用的 jQuery 與 jQuery UI 的 CDN 來源如下 :
# https://code.jquery.com/ (jQuery 官網)
# https://code.jquery.com/ui/ (jQuery UI 官網)
# https://docs.microsoft.com/en-us/aspnet/ajax/cdn/ (微軟)
# https://cdnjs.com/libraries/jqueryui (CDNJS)
# https://cdnjs.com/libraries/jquery (CDNJS)
# https://unpkg.com/
以下為使用最新版 jQuery, jQuery UI, DataTables 所製作的框架模板 :
<!--jqueryui.htm-->
{% extends "base.htm" %}
{% block link %}
<link id="theme" rel="stylesheet" href="https://code.jquery.com/ui/1.12.0/themes/hot-sneaks/jquery-ui.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.min.css">
{% endblock %}
{% block script %}
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
{% endblock %}
注意, 這裡連結 jquery-ui.css 的 link 元素特地給予一個 id 屬性, 這是為了使用者變更主題布景功能的緣故而設的. 其次, 此模板只是一個中間模板, 因此不須填入 body 區塊, 而由繼承此模板的 jQuery UI 應用模板填入.
2. EasyUI 專案模板 :
jQuery EasyUI 提供類似 ExtJS 華麗的 UI 元件, 提供免費 (freeware) 方案, 使用方式亦如其名好學好用, 是我最喜歡的前端 UI 框架, 環境配置參考 :
# 如何在 GAE 上佈署 jQuery EasyUI 專案 (二) : CDN 資源
常用的 CDN 如下 :
由於 EasyUI 官網提供了最新版本的 CDN 資源, 以此製作框架模板 easyui.htm 如下 :
{% extends "base.htm" %}
{% block link %}
<link id="theme" rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/default/easyui.css">
<link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/icon.css">
{% endblock %}
{% block script %}
<script src="http://www.jeasyui.com/easyui/jquery.min.js"></script>
<script src="http://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
<script src="http://www.jeasyui.com/easyui/locale/easyui-lang-zh_TW.js"></script>
{% endblock %}
同樣地, 這裡連結 easyui.css 的 link 元素特地給予一個 id 屬性, 這是為了使用者變更主題布景功能的緣故而設的.
3. Bootstrap 專案模板 :
Bootstrap 是源自 Twiter 內部的前端網頁框架, 包裝了許多 CSS 樣式表功能, 提供漂亮且外觀一致的好用元件, 可讓不擅長利用 CSS 進行網頁外觀與佈局設計的工程師快速建立專業與美觀的網頁.
常用的 Bootstrap 的 CDN 來源如下 :
# https://unpkg.com/
# https://cdnjs.com/libraries/bootstrap-table
# https://www.bootstrapcdn.com/
考慮 unpkg.com 有提供 bootstrap-table 的 CDN 支援, 以下使用 unpkg.com 來製作模板網頁 :
<!--bootstrap.htm-->
{% extends "base.htm" %}
{% block link %}
<link rel="stylesheet" href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.4/dist/bootstrap-table.min.css">
{% endblock %}
{% block script %}
<script src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"></script>
<script src="https://unpkg.com/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/bootstrap-table@1.15.4/dist/bootstrap-table.min.js"></script>
{% endblock %}
四. 框架專案綜合測試 :
以下根據上面所設計的框架專案模板網頁對 jQuery UI, EasyUI, 以及 Bootstrap 做個綜合測試, 主要對象是主題布景切換, 頁籤面板, 日期選擇器, 以及資料表格等元件.
1. 模板網頁 :
首先製作 home.htm 模板作為測試首頁, 此模板網頁包含全部測試之超連結 , 包含 jQuery UI, EasyUI, 以及 Bootstrap :
<!--home.htm-->
<!DOCTYPE html>
<html>
<head>
<title>前端框架模板模板測試</title>
<meta charset="utf-8">
</head>
<body>
<h3>前端框架模板測試</h3>
<ul>
<li><a href="/jqui_test_tabs">jQueryUI 頁嵌面板 Tabs</a></li>
<li><a href="/jqui_test_themes">jQueryUI 主題布景切換 Themes</a></li>
<li><a href="/jqui_test_datatables_array">jQueryUI 資料表格 DataTables (陣列)</a></li>
<li><a href="/jqui_test_datatables_ajax">jQueryUI 資料表格 DataTables (Ajax)</a></li>
<li><a href="/ezui_test_tabs">EasyUI 頁嵌面板 Tabs</a></li>
<li><a href="/ezui_test_themes">EasyUI 主題布景切換 themes</a></li>
<li><a href="/ezui_test_datagrid_ajax">EasyUI 資料表格 Datagrid (Ajax)</a></li>
<li><a href="/bootstrap_test_table_html">Bootstrap 表格 (HTML)</a></li>
<li><a href="/bootstrap_test_table_ajax">Bootstrap 表格 (Ajax)</a></li>
<li><a href="/bootstrap_test_jumbotron">Bootstrap 主題 (jumbotro)</a></li>
</ul>
</body>
</html>
(1). jQuery UI 應用的模板網頁 :
jQuery UI 應用模板全部都繼承 jqueryui.htm, 首先是頁籤測試之模板如下 :
<!--jqui_test_tabs.htm-->
{% extends "jqueryui.htm" %}
{% block style %}
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
{% endblock%}
{% block body %}
<div id="tabs">
<ul>
<li><a href="#tab1">頁籤 1</a></li>
<li><a href="/jqui_test_tab2">頁籤 2</a></li>
<li><a href="/jqui_test_tab3">頁籤 3</a></li>
</ul>
<div id="tab1">
<h3>這是頁籤 1 (網頁內提供)</h3>
</div>
</div>
<script>
$(document).ready(function(){
$("#tabs").tabs();
});
</script>
{% endblock%}
此網頁中的頁籤面板有三個頁籤, 第一個頁籤內容來自頁內, 另外兩個來自頁外. 第二個頁籤是載入一個模板網頁 jqui_test_tab2.htm, 此網頁很簡單, 只要網頁內容即可, 不需要完整 HTML 結構 (完整也可以) :
<!--jqui_test_tab2.htm-->
<h3>這是頁籤 {{ tab }} (模板 jqui_test_tab2.htm)</h3>
第三個頁籤內容不使用模板網頁, 而是在視圖程式 views.py 中以 HttpResponse() 函數直接回應 HTML 字串.
接著使用模板網頁 jqui_test_themes.htm 測試主題背景切換, 其中含有一個下拉式選單來選取主題, 並以日期選擇器 datepicker 元件來顯示主題之變化.
jQuery UI 頁籤測試用的模板 jqui_test_tabs.htm :
<!--jqui_test_themes.htm-->
{% extends "jqueryui.htm" %}
{% block style %}
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
{% endblock%}
{% block body %}
<select id="themes">
<option value="base">base</option>
<option value="black-tie">black-tie</option>
<option value="blitzer">blitzer</option>
<option value="cupertino">cupertino</option>
<option value="dark-hive">dark-hive</option>
<option value="dot-luv">dot-luv</option>
<option value="eggplant">eggplant</option>
<option value="excite-bike">excite-bike</option>
<option value="flick">flick</option>
<option value="hot-sneaks">hot-sneaks</option>
<option value="humanity">humanity</option>
<option value="le-frog">le-frog</option>
<option value="mint-choc">mint-choc</option>
<option value="overcast">overcast</option>
<option value="pepper-grinder">pepper-grinder</option>
<option value="redmond">redmond</option>
<option value="smoothness">smoothness</option>
<option value="south-street">south-street</option>
<option value="start">start</option>
<option value="sunny">sunny</option>
<option value="swanky-purse">swanky-purse</option>
<option value="trontastic">trontastic</option>
<option value="ui-darkness">ui-darkness</option>
<option value="ui-lightness">ui-lightness</option>
<option value="vader">vader</option>
</select><br><br>
<div id="datepicker"></div>
<script>
$(document).ready(function(){
$("#datepicker").datepicker();
$("#themes").selectmenu();
$("#themes").val("hot-sneaks");
$("#themes").selectmenu("refresh");
$('#themes').on('selectmenuchange', function() {
var theme=$(this).val();
var href="https://code.jquery.com/ui/1.12.0/themes/" + theme +
"/jquery-ui.min.css";
$("#theme").attr("href", href);
});
});
</script>
{% endblock%}
注意, 上面程式中是利用 jQueryUI 框架專案模板 jqueryui.htm 裡面特地加上的 link 元素 id 來變換主題布景樣式檔 jquery-ui.min.css 的上層路徑, 這樣便能套用不同主題之樣式檔.
最後兩個模板是測試 DataTables 用的, jqui_test_datatables_array.htm 是將資料直接寫在二維陣列中 (當然也可以從 views.py 中查詢資料庫後透過變數傳遞填入模板中).
<!--jqui_test_datatables_array.htm-->
{% extends "jqueryui.htm" %}
{% block style %}
body {
font-family: Arial, Helvetica, sans-serif;
font-size:14px;
}
.colclass {text-align:right;}
{% endblock%}
{% block body %}
<div id="container" style="width:500px;border:solid 1px;padding:5px;">
<table id="stocks"></table>
</div>
<script>
$(document).ready(function(){
var opt={"iDisplayLength":5,
"aLengthMenu":[5, 10, 15, 20],
"aoColumns":[{"sTitle":"股票名稱"},
{"sTitle":"股票代號"},
{"sTitle":"收盤價 (元)"},
{"sTitle":"成交量 (張)"}],
"aaData":[["台積電","2330",111.5,19268],
["中華電","2412",95.1,7096],
["中碳","1723",145.0,317],
["創見","2451",104.0,459],
["華擎","3515",104.0,95],
["訊連","5203",98.5,326]]
};
$("#stocks").dataTable(opt);
});
</script>
{% endblock%}
這裡我們給 DataTables 元件外面套上一個 div 元素, 目的是利用它來控制資料表格的樣式, 特別是寬度, 否則它預設是占滿整個螢幕寬度的.
另一個資料表格模板 jqui_test_datatables_ajax.htm 則是透過 Ajax 從後端取得要餵給 DataTables 的資料 :
<!--jqui_test_datatables_ajax.htm-->
{% extends "jqueryui.htm" %}
{% block style %}
body {
font-family: Arial, Helvetica, sans-serif;
font-size:14px;
}
{% endblock%}
{% block body %}
<div id="container" style="width:500px;border:solid 1px;padding:5px;">
<table id="stocks"></table>
</div>
<script>
$(document).ready(function(){
var opt={"iDisplayLength":5,
"aLengthMenu":[5, 10, 15, 20],
"bProcessing":true,
"aoColumns":[{"sTitle":"股票名稱","mData":"stock_name"},
{"sTitle":"股票代號","mData":"stock_id"},
{"sTitle":"收盤價 (元)","mData":"close"},
{"sTitle":"成交量 (張)","mData":"volumn"}],
"sAjaxSource":"/get_stocks_list"
};
$("#stocks").dataTable(opt);
});
</script>
{% endblock%}
此網頁中是透過 sAjaxSource 選項來指定提供資料的後端程式名稱 get_stocks_list, 透過 urls.py 對映到 views.py 裡面的 get_stocks_list() 函數, 其輸出是以 "aaData" 為鍵的 JSON 格式資料 :
{"aaData": [{"stock_name": "\u53f0\u7a4d\u96fb", "stock_id": "2330", "close": 111.5, "volumn": 19268}, {"stock_name": "\u4e2d\u83ef\u96fb", "stock_id": "2412", "close": 95.1, "volumn": 7096}, {"stock_name": "\u4e2d\u78b3", "stock_id": "1723", "close": 145.0, "volumn": 317}, {"stock_name": "\u5275\u898b", "stock_id": "2451", "close": 104.0, "volumn": 459}, {"stock_name": "\u83ef\u64ce", "stock_id": "3515", "close": 104.0, "volumn": 95}, {"stock_name": "\u8a0a\u9023", "stock_id": "5203", "close": 98.5, "volumn": 326}]}
注意, 使用 Ajax 方式取得資料時, "aoColumns" 選項中必須用 "mData" 鍵定義表格的欄位名稱才行.
(2). EasyUI 應用的模板網頁 :
EasyUI 應用模板全部都繼承 easyui.htm, 首先是頁籤面板測試的模板 :
<!--ezui_test_tabs.htm-->
{% extends "easyui.htm" %}
{% block style %}
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
{% endblock%}
{% block body %}
<div id="tabs" class="easyui-tabs">
<div title="頁籤 1" style="padding:10px;">這是頁籤 1</div>
<div title="頁籤 2" style="padding:10px;" data-options="href:'/ezui_test_tab2'"></div>
<div title="頁籤 3" style="padding:10px;" data-options="href:'/ezui_test_tab3'"></div>
</div>
{% endblock%}
與上面 jQuery UI 測試一樣有三個頁籤, 第一個頁籤內容來自頁內, 後兩個則來自後端 Ajax 來源提供, 第二個是透過簡單的模板網頁 ezui_test_tab2.htm :
<!--ezui_test_tab2.htm-->
<h3>這是頁籤 {{ tab }} (模板 ezui_test_tab2.htm)</h3>
第三個則是由 views.py 直接回應, 不需要用到模板.
其次是主題布景切換 :
<!--ezui_test_themes.htm-->
{% extends "easyui.htm" %}
{% block style %}
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
{% endblock%}
{% block body %}
<select id="theme_sel" class="easyui-combobox" style="width:120px" panelHeight="320">
<option value="default" selected>default</option>
<option value="gray">gray</option>
<option value="black">black</option>
<option value="bootstrap">bootstrap</option>
<option value="metro">metro</option>
<option value="metro-blue">metro-blue</option>
<option value="metro-gray">metro-gray</option>
<option value="metro-green">metro-green</option>
<option value="metro-orange">metro-orange</option>
<option value="metro-red">metro-red</option>
<option value="ui-cupertino">ui-cupertino</option>
<option value="ui-dark-hive">ui-dark-hive</option>
<option value="ui-pepper-grinder">ui-pepper-grinder</option>
<option value="ui-sunny">ui-sunny</option>
</select><br><br>
<input id="datebox1" type="text" class="easyui-datebox">
<script>
$(document).ready(function() {
$("#theme_sel").combobox({
onSelect:function(rec){
var css="http://www.jeasyui.com/easyui/themes/" +
rec.value + "/easyui.css";
$("#theme").attr("href", css);
}
});
});
</script>
{% endblock%}
這裡使用了 EasyUI 的 Combobox 元件當作下拉式選單, 透過其 onSelect 事件傳回的 rec 物件取得所選之主題, 然後更改 easyui.htm 模板中 id=theme 的 link 元素的 href 即可變更主題布景. 以上參考 :
# 用 jQuery EasyUI 打造輕量級 CMS (五)
最後是資料表格 Datagrid 測試模板 :
<!--ezui_test_datagrids.htm-->
{% extends "easyui.htm" %}
{% block style %}
body{
font-family:verdana,helvetica,arial,sans-serif;
padding:20px;
font-size:12px;
margin:0;
}
{% endblock%}
{% block body %}
<table class="easyui-datagrid" title="股票列表" style="width:500px;"
data-options="url:'/get_stocks_list_ezui',method:'get'">
<thead>
<tr>
<th data-options="field:'stock_name',width:100">股票名稱</th>
<th data-options="field:'stock_id',width:100">股票代號</th>
<th data-options="field:'close',width:100">收盤價 (元)</th>
<th data-options="field:'volumn',width:100">成交量</th>
</tr>
</thead>
</table>
{% endblock%}
只要用 data-options 並指定 href 屬性即可以 Ajax 方式從後端程式 get_stocks_list_ezui 取得資料, 但必須在表格標題 thead 的 th 元素中指定 field 欄位名稱才行. EasyUI 的 Datagrids 要求後端程式回應一個具有 total (總筆數) 與 rows (紀錄陣列) 屬性之 JSON 格式資料, 例如 :
{"totals": "6", "rows": [{"stock_name": "\u53f0\u7a4d\u96fb", "stock_id": "2330", "close": 111.5, "volumn": 19268}, {"stock_name": "\u4e2d\u83ef\u96fb", "stock_id": "2412", "close": 95.1, "volumn": 7096}, {"stock_name": "\u4e2d\u78b3", "stock_id": "1723", "close": 145.0, "volumn": 317}, {"stock_name": "\u5275\u898b", "stock_id": "2451", "close": 104.0, "volumn": 459}, {"stock_name": "\u83ef\u64ce", "stock_id": "3515", "close": 104.0, "volumn": 95}, {"stock_name": "\u8a0a\u9023", "stock_id": "5203", "close": 98.5, "volumn": 326}]}
模板中 th 的 field 屬性必須對照此 JSON 資料中 rows 陣列每一個字典之 鍵 (key).
(3). Bootstrap 測試的模板網頁 :
Bootstrap 應用模板全部都繼承 bootstrap.htm, 首先是頁籤面板測試的模板, 第一個是將頁籤內容直接寫在網頁內 :
<!--bootstrap_test_table_html.htm-->
{% extends "bootstrap.htm" %}
{% block style %}
{% endblock%}
{% block body %}
<div class="container" style="width:600px;">
<table class="table table-responsive table-striped table-condensed table-bordered table-hover">
<tr>
<th>股票名稱</th>
<th>股票代號</th>
<th>收盤價 (元)</th>
<th>成交量
</tr>
<tr>
<td>台積電</td>
<td>2330</td>
<td>111.5</td>
<td>19268</td>
</tr>
<tr>
<td>中華電</td>
<td>2412</td>
<td>95.1</td>
<td>7096</td>
</tr>
<tr>
<td>中碳</td>
<td>1723</td>
<td>145.0</td>
<td>317</td>
</tr>
<tr>
<td>創見</td>
<td>2451</td>
<td>104.0</td>
<td>459</td>
</tr>
<tr>
<td>華擎</td>
<td>3515</td>
<td>108.5</td>
<td>95</td>
</tr>
<tr>
<td>訊連</td>
<td>5203</td>
<td>98.5</td>
<td>326</td>
</tr>
</table>
</div>
{% endblock%}
第二個是以 data-url 屬性透過 Ajax 從後端程式 get_stocks_list 取得資料來源 :
<!--bootstrap_test_table_ajax.htm-->
{% extends "bootstrap.htm" %}
{% block style %}
{% endblock%}
{% block body %}
<div class="container" style="width:600px;">
<table id="stocks" class="table table-responsive table-striped table-condensed table-bordered table-hover" data-url='/get_stocks_list'>
<thead>
<tr>
<th data-field="stock_name">股票名稱</th>
<th data-field="stock_id">股票代號</th>
<th data-field="close">收盤價 (元)</th>
<th data-field="volumn">成交量
</tr>
</thead>
</table>
</div>
<script>
$(document).ready(function(){
$.ajax({
url: '/get_stocks_list',
dataType: 'json',
success: function(data) {
//alert(JSON.stringify(data.aaData));
$('#stocks').bootstrapTable({
data: data.aaData
});
},
error: function(e) {
console.log(e.responseText);
}
});
});
</script>
{% endblock%}
注意, , 後端程式 get_stocks_list 是上面 jQuery UI 測試時使用的, Bootstrap 的表格需要的遠端資料格式為一個物件陣列 :
[{"stock_name": "\u53f0\u7a4d\u96fb", "stock_id": "2330", "close": 111.5, "volumn": 19268}, {"stock_name": "\u4e2d\u83ef\u96fb", "stock_id": "2412", "close": 95.1, "volumn": 7096}, {"stock_name": "\u4e2d\u78b3", "stock_id": "1723", "close": 145.0, "volumn": 317}, {"stock_name": "\u5275\u898b", "stock_id": "2451", "close": 104.0, "volumn": 459}, {"stock_name": "\u83ef\u64ce", "stock_id": "3515", "close": 104.0, "volumn": 95}, {"stock_name": "\u8a0a\u9023", "stock_id": "5203", "close": 98.5, "volumn": 326}]
這好就是 jQuery UI 資料表格遠端內容中的 aaData 屬性, 因此上面 bootstrapTable() 的 data 屬性就要取 data.aaData 值給它, 不是 get_stocks_list 的整個傳回值 data.
最後一個 Bootstrap 模板是測試 Jumbotro 主題網頁, 這是參考書上範例改寫標題而得 :
<!--bootstrap_test_jumbotron.htm-->
{% extends "bootstrap.htm" %}
{% block style %}
{% endblock%}
{% block body %}
<div class="jumbotron">
<div class="container">
<h1>埃及法老王木乃伊展</h1>
<p>即日起開放訂票</p>
<p>
<a class="btn btn-primary btn-lg" href="#" role="button">
購票 »
</a>
</p>
</div>
</div>
{% endblock%}
只要指定 div 的 class 為 Jumbotron 即可馬上幫網頁套上美麗外衣, 這就是 Bootstrap 受到缺乏美感工程師熱愛的原因.
2. URL 處理函數 urls.py :
路由處理程式 urls.py 用來將可能接收到的 URL 對映到視圖處理程式 views.py 中的函數, 由函數決定如何回應客戶端 (包含隱性的 URL 要求例如 Ajax) :
#urls.py
from django.contrib import admin
from django.urls import path
import mysite.views as views
urlpatterns = [
path('admin/', admin.site.urls),
path('jqui_test_tabs/', views.jqui_test_tabs),
path('jqui_test_tab2/', views.jqui_test_tab2),
path('jqui_test_tab3/', views.jqui_test_tab3),
path('jqui_test_themes/', views.jqui_test_themes),
path('jqui_test_datatables_array/', views.jqui_test_datatables_array),
path('jqui_test_datatables_ajax/', views.jqui_test_datatables_ajax),
path('get_stocks_list/', views.get_stocks_list),
path('ezui_test_tabs/', views.ezui_test_tabs),
path('ezui_test_tab2/', views.ezui_test_tab2),
path('ezui_test_tab3/', views.ezui_test_tab3),
path('ezui_test_themes/', views.ezui_test_themes),
path('ezui_test_datagrid_ajax/', views.ezui_test_datagrid_ajax),
path('get_stocks_list_ezui/', views.get_stocks_list_ezui),
path('bootstrap_test_table_html/', views.bootstrap_test_table_html),
path('bootstrap_test_table_ajax/', views.bootstrap_test_table_ajax),
path('bootstrap_test_jumbotron/', views.bootstrap_test_jumbotron),
path('', views.home),
]
3. 視圖處理函數 views.py :
視圖處理函數 views.py 負責處理 urls.py 丟過來的 URL 請求 :
#views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.http import JsonResponse
from datetime import datetime
def jqui_test_tabs(request):
return render(request, 'jqui_test_tabs.htm', {})
def jqui_test_tab2(request):
tab=2
return render(request, 'jqui_test_tab2.htm', locals())
def jqui_test_tab3(request):
return HttpResponse("<h3>這是頁籤 3 (直接回應)</h3>")
def jqui_test_themes(request):
return render(request, 'jqui_test_themes.htm', {})
def jqui_test_datatables_array(request):
return render(request, 'jqui_test_datatables_array.htm', {})
def jqui_test_datatables_ajax(request):
return render(request, 'jqui_test_datatables_ajax.htm', {})
def get_stocks_list(request):
data={"aaData":[{"stock_name":"台積電",
"stock_id":"2330",
"close":111.5,
"volumn":19268},
{"stock_name":"中華電",
"stock_id":"2412",
"close":95.1,
"volumn":7096},
{"stock_name":"中碳",
"stock_id":"1723",
"close":145.0,
"volumn":317},
{"stock_name":"創見",
"stock_id":"2451",
"close":104.0,
"volumn":459},
{"stock_name":"華擎",
"stock_id":"3515",
"close":104.0,
"volumn":95},
{"stock_name":"訊連",
"stock_id":"5203",
"close":98.5,
"volumn":326}]}
return JsonResponse(data)
def ezui_test_tabs(request):
return render(request, 'ezui_test_tabs.htm', {})
def ezui_test_tab2(request):
tab=2
return render(request, 'ezui_test_tab2.htm', locals())
def ezui_test_tab3(request):
return HttpResponse("<h3>這是頁籤 3 (直接回應)</h3>")
def ezui_test_themes(request):
return render(request, 'ezui_test_themes.htm', {})
def ezui_test_datagrid_ajax(request):
return render(request, 'ezui_test_datagrid_ajax.htm', {})
def get_stocks_list_ezui(request):
data={"totals":"6",
"rows":[{"stock_name":"台積電",
"stock_id":"2330",
"close":111.5,
"volumn":19268},
{"stock_name":"中華電",
"stock_id":"2412",
"close":95.1,
"volumn":7096},
{"stock_name":"中碳",
"stock_id":"1723",
"close":145.0,
"volumn":317},
{"stock_name":"創見",
"stock_id":"2451",
"close":104.0,
"volumn":459},
{"stock_name":"華擎",
"stock_id":"3515",
"close":104.0,
"volumn":95},
{"stock_name":"訊連",
"stock_id":"5203",
"close":98.5,
"volumn":326}]}
return JsonResponse(data)
def bootstrap_test_table_html(request):
return render(request, 'bootstrap_test_table_html.htm', {})
def bootstrap_test_table_ajax(request):
return render(request, 'bootstrap_test_table_ajax.htm', {})
def bootstrap_test_jumbotron(request):
return render(request, 'bootstrap_test_jumbotron.htm', {})
def home(request):
return render(request, 'home.htm', {})
這裡比較特別之處是回應 Ajax 要求需使用 django.http.JsonResponse() 函數, DataTables 元件要求回應一個以 aaData 為鍵的 JSON 資料. 參考 :
# jQuery 套件 DataTables 的測試
4. 測試結果 :
以上檔案準備好後以 python manage.py runserver 指令啟動開發伺服器, 首先是瀏覽 127.0.0.1:8000 顯示首頁 :
jQuery UI 測試結果如下 :
可見當資料長度超過每頁筆數時就會出現換頁按鈕. DataTables 雖然昇版後有些選項功能已被廢棄, 但大部分都還是被保留.
EasyUI 測試結果如下 :
注意, EasyUI 新版的 datagrid 元件在表格標頭部分似乎有 bug, 長度比表格內容本身稍短, 但在舊版卻不會有這種情形.
最後是 Bootstrap 的測試結果 :
參考 :
# jQuery UI 學習筆記 (一) : 主題布景 (Themes)
# jQuery UI 學習筆記索引
# https://datatables.net/upgrade/1.10-convert#Options
# https://datatables.net/reference/option/ajax
# [JQuery] $.ajax 存取 Json 簡單範例
# TypeError: $ (…).bootstrapTable is not a function
2019-10-10 補充 :
修改了近一周終於把三個主要框架的 Django 模板搞定了, 順便把 PHP 測試網站移到 000a.biz 去. 框架久沒有用真的會生疏, 還好當時有留下完整測試紀錄, 要回復記憶不難, 倒是版本變更較麻煩, CDN 雖然很方便, 但可以的話還是保留一份測試 ok 的框架版本在本地主機上比較好. 另外我覺得 Bootstrap 有空值得學一學.
2021-03-09 補充 :
Django 3 對模板路徑有新做法, 參考 :
沒有留言 :
張貼留言