Django使用Datatables插件總結
文章中的例子已上傳至github
基本使用
Datatables插件是一款方便簡單的展示數據的列表插件。關於基本使用,官方網站上的已介紹的很詳細,這里我再稍微過一下。
1. js配置。包含jquery和datatables的js
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script stc="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
2. css配置。包含dataTables的css
```css
<link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet">
```
3. html。初始化表格
```html
<table id="example" class="display" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011/07/25</td>
<td>$170,750</td>
</tr>
<tr>
<td>Ashton Cox</td>
<td>Junior Technical Author</td>
<td>San Francisco</td>
<td>66</td>
<td>2009/01/12</td>
<td>$86,000</td>
</tr>
</tbody>
</table>
```
4. js配置。是表格dataTable化
```javascript
<script type="text/javascript">
$(document).ready(function() {
$('#example').DataTable();
} );
</script>
```
與django結合使用
這里以一個展示用戶姓名年齡的表格舉例。假設數據庫(數據庫使用Django默認自帶數據庫)中有表格User,它的字段有name、age兩項。
基本使用
基本使用的話,則是django作為后端,將要顯示的數據傳給DataTables進行展示。具體用法比較簡單,DataTables的官網也很詳細了。(官網文檔都是第一份資料)
不多說,直接上代碼
def get_basic_tables(request):
"""
創建基本的DataTables表格
"""
user_list = []
for user_info in User.objects.all():
user_list.append({
'name': user_info.name,
'age': user_info.age
})
return render(request, 'example/basic_tables.html', {
'users': user_list
})
上面代碼主要就是將數據取出並返回。
前端的展示代碼如下:
<table id="basic-table" class="table table-hover" width="100%">
<thead>
<tr>
<th>學號</th>
<th>姓名</th>
<th>年齡</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
$(document).ready(function () {
$("#basic-table").DataTable({
// 表下方頁腳的類型,具體類別比較到,見[官網](https://datatables.net/examples/basic_init/alt_pagination.html)
"pagingType": "simple_numbers",
//啟動搜索框
searching: true,
destroy : true,
// 保存刷新時原表的狀態
stateSave: true,
// 將顯示的語言初始化為中文
"language": {
"lengthMenu": "選擇每頁 _MENU_ 展示 ",
"zeroRecords": "未找到匹配結果--抱歉",
"info": "當前顯示第 _PAGE_ 頁結果,共 _PAGES_ 頁",
"infoEmpty": "沒有數據",
"infoFiltered": "(獲取 _MAX_ 項結果)",
"paginate": {
"first": "首頁",
"previous": "上一頁",
"next": "下一頁",
"last": "末頁"
}
},
// 此處重要,該data就是dataTables要展示的數據.users即為后台傳遞過來的數據
data: {{ users | safe }},
columns: [
{
data: null,
width: "1%",
// 若想前端顯示的不一樣,則需要"render"函數
'render': function (data, type, full, meta) {
return meta.row + 1 + meta.settings._iDisplayStart;
}
},
{
data: "name",
'render': function (data, type, full, meta) {
return '<a class="text-warning" style="color:#007bff" title="年齡為'+ full.age +'">'+ data +'</a>';
}
},
{data: 'age'}
]
})
});
可以看到html中只初始化了表頭,表的內容則在javascript中控制。最終顯示出來的數據行,第一列是對表格數據的排序。從代碼中看出,當data對應的數據被置為null時,單元格中的內容將由"render"對應的函數返回值決定。第一列datarender函數中meta.row相當於表格中行的索引,默認是從0開始,故為了學號顯示從1開始,進行了加1操作。
render函數中的四個參數可謂是大有作用。 參數data剛好就是該函數上方“data”鍵對應的值的內容,比如第二列中的數據為‘data”鍵的值為name,則render函數中data就是name。而參數full相當於后端傳遞過來的users中的每個user的索引,這樣某一個單元格的內容想與它所在行的其他單元格進行互動,則可用full參數來傳遞。表格中當使用鼠標移動到名字上時,會顯示到該人名的年齡,這一功能就是使用了full:
{
data: "name",
'render': function (data, type, full, meta) {
return '<a class="text-warning" style="color:#007bff" title="年齡為'+ full.age +'">'+ data +'</a>';
}
},
ajax請求數據使用
基本操作
這種使用方法,則是前端發送ajax請求去后端獲取數據,而不是一開始就有后端將數據傳送到前端的。當數據再由后端傳遞回前端時,前端會自己進行處理,如分頁等。下面例子是展示年齡為22周歲的人員表格
<table id="ajax-table" class="table table-hover" width="100%">
<thead>
<tr>
<th>學號</th>
<th>姓名</th>
<th>年齡</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
html頁面中依舊只是初始化了表頭。
$(document).ready(function () {
//django post請求需要加認證,不能忘了
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' }
});
var table = $('#ajax-table').DataTable({
"pagingType": "full_numbers",
// 跟基本使用對比,已經沒有data屬性,而是多了"ajax"
"ajax":{
"processing": true,
// ajax請求的網址
"url": "{% url 'example:request_ajax' %}",
"type": 'POST',
"data": {
// 前端向后端傳遞的數據age,比如只查詢年齡在22歲的人員
"age": 22
},
//
"dataSrc": ""
},
// ajax請求成功傳遞回來后數據的展示
columns: [
{
data: null,
width: "1%",
// 若想前端顯示的不一樣,則需要"render"函數
'render': function (data, type, full, meta) {
return meta.row + 1 + meta.settings._iDisplayStart;
}
},
{
data: "name",
'render': function (data, type, full, meta) {
return '<a class="text-warning" style="color:#007bff" title="年齡為'+ full.age +'">'+ data +'</a>';
}
},
{data: 'age'}
],
"language": {
"processing": "正在獲取數據,請稍后...",
"lengthMenu": "選擇每頁 _MENU_ 展示 ",
"zeroRecords": "未找到匹配結果--抱歉",
"info": "當前顯示第 _PAGE_ 頁結果,共 _PAGES_ 頁, 共 _TOTAL_ 條記錄",
"infoEmpty": "沒有數據",
"infoFiltered": "(獲取 _MAX_ 項結果)",
"sLoadingRecords": "載入中...",
"paginate": {
"first": "首頁",
"previous": "上一頁",
"next": "下一頁",
"last": "末頁"
}
}
} );
});
后端代碼處理ajax請求:
def request_ajax(request):
"""
處理ajax的例子中的post請求
:param request:
:return:
"""
try:
if request.method == "POST":
# print(request.POST)
# 獲取到前端頁面ajax傳遞過來的age
age = int(request.POST.get('age', 22))
user_list = []
for user_info in User.objects.filter(age=age):
user_list.append({
'name': user_info.name,
'age': user_info.age
})
# 主要是將數據庫查詢到的數據轉化為json形式返回給前端
return HttpResponse(json.dumps(user_list), content_type="application/json")
else:
return HttpResponse(f'非法請求方式')
except Exception as e:
return HttpResponse(e.args)
相比來看跟基本使用沒多少區別,只是多了一步ajax請求而已。
后端分頁
當我們要往前端展示的數據量過大時,如果還是一股腦將數據全部扔給前端來處理,那么你會發現前端分頁加載的性能很差,這時我們可以將分頁操作放到后端來做。
其實將分頁放到后端的意思就是對后台數據庫中的數據進行部分請求。我們首先可以這樣想:“用戶在前端頁面查看表格時,他其實只關心這一頁數據,他看不到其他頁的數據。要看到其他頁的數據,他必須得點擊網頁中的上一頁或下一頁按鈕。” 理解了這一點,我們是否可以這樣做,即:“用戶想看哪一頁的數據,我就只去后台數據庫查詢這一頁的數據。” 有了這樣的理解,下來就是具體操作了。這個思路其實類似與Python語法中列表的切片功能,例如:
test_list = [1, 3, 4, 5, 6, 7, 8, 9, 10, 11]
# 測試我們只需要這個列表中第3個到6個這4條數據,那么用列表的切片
little_list = test_list[2:6]
要查詢到某一頁展示的數據是哪些,必須知道這一頁的數據的對應的數據起始位置和結束位置。
恰好在DataTables中,每次用戶點擊翻頁(上一頁或下一頁)按鈕時,前端都會向后端發送一次ajax請求。 而這次請求,前端則會將這一頁的起始位置與結束位置傳遞到后端。
下面上代碼:
<table id="basic-table" class="table table-hover" width="100%">
<thead>
<tr>
<th>學號</th>
<th>姓名</th>
<th>年齡</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
$(document).ready(function () {
//django post請求需要加認證,不能忘了
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' }
});
var table = $('#backend-table').DataTable({
"pagingType": "full_numbers",
// 跟基本使用對比,已經沒有data屬性,而是多了"ajax"
searching: false,
destroy: true,
stateSave: true,
// 此處為ajax向后端請求的網址
sAjaxSource: "{% url 'example:request_backend' %}",
"processing": false,
"serverSide": true,
"bPaginate" : true,
"bInfo" : true, //是否顯示頁腳信息,DataTables插件左下角顯示記錄數
"sDom": "t<'row-fluid'<'span6'i><'span6'p>>",//定義表格的顯示方式
//服務器端,數據回調處理
"fnServerData" : function(sSource, aoData, fnCallback) {
$.ajax({
"dataType" : 'json',
// 此處用post,推薦用post形式,get也可以,但可能會遇到坑
"type" : "post",
"url" : sSource,
"data" : aoData,
"success" : function(resp){
fnCallback(resp);
}
});
},
// ajax請求成功傳遞回來后數據的展示
columns: [
{
data: null,
width: "1%",
// 若想前端顯示的不一樣,則需要"render"函數
'render': function (data, type, full, meta) {
return meta.row + 1 + meta.settings._iDisplayStart;
}
},
{
data: "name",
'render': function (data, type, full, meta) {
return '<a class="text-warning" style="color:#007bff" title="年齡為'+ full.age +'">'+ data +'</a>';
}
},
{data: 'age'}
],
"language": {
"processing": "正在獲取數據,請稍后...",
"lengthMenu": "選擇每頁 _MENU_ 展示 ",
"zeroRecords": "未找到匹配結果--抱歉",
"info": "當前顯示第 _PAGE_ 頁結果,共 _PAGES_ 頁, 共 _TOTAL_ 條記錄",
"infoEmpty": "沒有數據",
"infoFiltered": "(獲取 _MAX_ 項結果)",
"sLoadingRecords": "載入中...",
"paginate": {
"first": "首頁",
"previous": "上一頁",
"next": "下一頁",
"last": "末頁"
}
}
} );
// 每隔5秒刷新一次數據
// setInterval(refresh, 5000);
});
function refresh() {
var table = $('#backend-table').DataTable();
table.ajax.reload(null, false); // 刷新表格數據,分頁信息不會重置
}
后端代碼:
# 暫時跳過csrf的保護
@csrf_exempt
def request_backend(request):
"""
處理后端分頁例子中的post請求
:param request:
:return:
"""
try:
if request.method == "POST":
# 獲取翻頁后該頁要展示多少條數據。默認為10;此時要是不清楚dataTables的ajax的post返回值
# 可以打印一下看看print(request.POST)
page_length = int(request.POST.get('iDisplayLength', '10'))
# 該字典將轉化為json格式的數據返回給前端,字典中的key默認的名字不能變
rest = {
"iTotalRecords": page_length, # 本次加載記錄數量
}
# 獲取傳遞過來的該頁的起始位置,第一頁的起始位置為0.
page_start = int(request.POST.get('iDisplayStart', '0'))
# 該頁的結束位置則就是"開始的值 + 該頁的長度"
page_end = page_start + page_length
# 開始查詢數據庫,只請求這兩個位置之間的數據
users = User.objects.all()[page_start:page_end]
total_length = User.objects.all().count()
user_list = []
for user_info in users:
user_list.append({
'name': user_info.name,
'age': user_info.age
})
# print(start, ":", length, ":", draw)
# 此時的key名字就是aaData,不能變
rest['aaData'] = user_list
# 總記錄數量
rest['iTotalDisplayRecords'] = total_length
return HttpResponse(json.dumps(rest), content_type="application/json")
else:
return HttpResponse(f'非法請求方式')
except Exception as e:
return HttpResponse(e.args)
如果我們想讓前端實現定時刷新,可以用js的setInterval方法。具體如下:
function refresh() {
var table = $('#backend-table').DataTable();
table.ajax.reload(null, false); // 刷新表格數據,分頁信息不會重置
}
// 每隔5秒刷新一次數據
setInterval(refresh, 5000);
最后
以上的還有好多的dataTables插件的方法沒有使用到,官網有很多的使用事例,也非常詳細,此處也只是把常用到的進行了歸納。這里多說一句,關於ajax請求后DataTables默認的查詢會不起作用,但它會將查詢框中的text通過ajax返回,需要自己在后端進行處理。
以上內容若有錯誤,請及時指正哈!