DjangoWeb使用Datatable進行後端分頁的實現
使用場景:不使用Django的模版語言進行分頁(網上大多數都使用該方式),使用Jquery DataTable.js 外掛進行分頁處理。
本人做的是一個表格監控頁面,該頁面中的table內容每5s重新整理一次。
注意:這種方式非長連線(websocket)模式,長連線模式也有弊端,因網路波動導致,倘若一次連線斷開,後面將無法繼續重新整理資料(不重連的話),且比較吃伺服器頻寬。
故使用Ajax定時重新整理獲取最新資料,兩種方案各有優劣,根據實際場景進行抉擇。
程式碼如下:
1.Html頁面內容(本人用的是Admin.lte的前端框架),
引入Datatable css 和 Js,並建立一個table:
<link rel="stylesheet" href="{% static '/plugins/bootstrap-datatable/bootstrap-table.css' %}" rel="external nofollow" > <link rel="stylesheet" href="{% static '/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css' %}" rel="external nofollow" > <table class="table table-bordered table-striped table-hover" id="monitorTable" style="width: 100%"> </table> <script src="{% static '/bower_components/datatables.net/js/jquery.dataTables.min.js' %}"></script> <script src="{% static '/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js' %}"></script>
2.頁面載入時本人對錶格內容進行了初始化,下面的兩種方式對錶格都能進行初始化,但是獲取到的var 物件是不一樣的。
這裡一定要注意(分不清楚就是個坑):
以var table1=$("#xxx").Datatable({})
以var table2=$("#xxx").datatable({})
即table1!=table2
這裡要說明下,上面的table1是物件,table2是API物件(請對這句話保持警惕),建議初始化表格時使用table1的方式。
根據官網的描述DataTables的真正威力可以通過使用它提供的API來利用。
關於table2的使用,以後會說明!!!
3.因為同一頁面可能使用多個表格,所以我要多個表格共用的部分提取出來,避免程式碼反覆編寫:
下面的方法定義了3個引數,
lengthMenuParam:table表格左上角的分頁列表“右側”需要顯示哪些內容(這部分可以自定義)
urlParam:table中的資料從哪裡獲取
columnsParam:table中有哪些列內容
這裡要注意下,bProcessing=True這個屬性很重要,這個屬效能很友好的提醒使用者資料正在讀取中,因為讀取伺服器資料是要時間的。
// table初始化方法 function initDataTable(lengthMenuParam,urlParam,columnsParam) { return { sPaginationType: "full_numbers",//分頁風格,full_number會把所有頁碼顯示出來 searching: false,//搜尋 ordering: false,//是否啟用排序 bProcessing: true,//是否顯示載入 sAjaxSource: urlParam,//請求資源路徑 serverSide: true,//開啟伺服器處理模式 /* 使用ajax,在服務端處理資料 sSource:即是"sAjaxSource" aoData:要傳遞到服務端的引數 fnCallback:處理返回資料的回撥函式 */ fnServerData: function (sSource,aoData,fnCallback) { $.ajax({ 'type': 'POST',"url": sSource,"dataType": "json","data": {"aodata": JSON.stringify(aoData)},"success": function (resp) { fnCallback(resp); } }); },"oLanguage": {//語言設定 "sLengthMenu": '<select class="form-control" style="width:150px">' + '<option value="10" selected>每頁10條</option>' + '<option value="20">每頁20條</option>' + '<option value="50">每頁50條</option>' + '<option value="100">每頁100條</option>' + '</select>' + lengthMenuParam,"sProcessing": "處理中...","sZeroRecords": "沒有匹配結果","sInfo": "顯示第 _START_ 至 _END_ 項結果,共 _TOTAL_ 項","sInfoEmpty": "沒有資料","sInfoFiltered": "(獲取 _MAX_ 項結果)","sInfoPostFix": "","sSearch": "搜尋:","sUrl": "","sEmptyTable": "表中資料為空","sLoadingRecords": "載入中...","sInfoThousands": ",","oPaginate": { "sFirst": "首頁","sPrevious": "上頁","sNext": "下頁","sLast": "末頁" },},"bProcessing": true,//開啟讀取伺服器資料時顯示正在載入中……特別是大資料量的時候,開啟此功能比較好 "bServerSide": true,//開啟伺服器模式,使用伺服器端處理配置datatable。 // 注意:sAjaxSource引數也必須被給予為了給datatable原始碼來獲取所需的資料對於每個畫。 // 這個翻譯有點彆扭。開啟此模式後,你對datatables的每個操作 每頁顯示多少條記錄、下一頁、上一頁、排序(表頭)、搜尋,這些都會傳給伺服器相應的值。 "columns": columnsParam,} }
定義左側顯示引數:
var lengthMenuParam = '<div class="btn-group">' + '<button type="button" class="btn btn-default" data-toggle="modal" data-target="#addResources_modal">新增</button>' + '<button type="button" class="btn btn-default selectAllCheck">全選</button>' + '<button type="button" class="btn btn-default" id="selectAllDelete">刪除</button>' + '</div>';
定義url地址:
var urlParam = "{% url 'Monitor:monitor' %}";
定義列內容:
var columnsParam = [ {title: "id",data: "id",sClass: "hidden"},{ data: null,sWidth: "1%",'render': function (data,type,full,meta) { return meta.row + 1 + meta.settings._iDisplayStart; } },{ title: '<input type="checkbox" class="selectAllCheck">',data: null,meta) { return '<div><input type="checkbox"></div>'; } },{title: "名稱",data: "name"},{ title: "IP",data: "ip","render": function (data,meta) { var strDelete = '<a href="/docker/container?ip=' + data + '" rel="external nofollow" class="text-blue">' + data + '</a>'; return strDelete; } },{title: "作業系統",data: "os"},{title: "狀態",data: "status"},{title: "建立日期",data: "createTime"},meta) { var strModify = "<button type='button' class='btn btn-warning btn-xs btn-flat modifyResources' data-toggle='modal' data-target='#modifyResources_modal'> <i class='fa fa-pencil'></i>修改</button > "; var strDelete = "<button type='button' class='btn btn-danger btn-xs btn-flat deleteResources' > <i class='fa fa-pencil'></i>刪除</button > "; return strModify + strDelete; } },];
上面的列內容中,第1列是隱藏內容,第2列是行序號,第3列check(用來多選的),
第4,6,7,8列是要顯示的資訊,第5列是超連結。
第9列是操作按鈕(根據自己的選擇增加、刪除)。
一般情況下,上述內容已經夠用了。
4.完成表格的初始化:
$("#monitorTable").DataTable( initDataTable(lengthMenuParam,columnsParam) )
注意,我這裡的datatable分頁使用的是post請求, 因為分頁的時候需要向服務端傳遞很多引數,使用get請求的話,這裡就很難受了。
5.服務端程式碼,返回結果的內容格式是固定的,不要想著去修改:
@csrf_exempt def monitor(request): if request.method == 'GET': return render(request,'monitor/Monitor.html',) else: dataTable = {} aodata = json.loads(request.POST.get("aodata")) for item in aodata: if item['name'] == "sEcho": sEcho = int(item['value']) # 客戶端傳送的標識 if item['name'] == "iDisplayStart": iDisplayStart = int(item['value']) # 起始索引 if item['name'] == "iDisplayLength": iDisplayLength = int(item['value']) # 每頁顯示的行數 # 獲取最新的時間 last_time = T_Monitor.objects.order_by('-createTime').first().createTime # 根據最新的時間獲取監控資料 monitor_list = T_Monitor.objects.filter(createTime=last_time).order_by('createTime') #monitor_list = T_Monitor.objects.order_by('updateTime').all() resultLength = monitor_list.count() # 對list進行分頁 paginator = Paginator(monitor_list,iDisplayLength) # 把資料分成10個一頁。 try: monitor_list = paginator.page(iDisplayStart / 10 + 1) # 請求頁數錯誤 except PageNotAnInteger: monitor_list = paginator.page(1) except EmptyPage: monitor_list = paginator.page(paginator.num_pages) data=[] for item in monitor_list: row = {"id": str(item.id),"name": item.name,"ip": item.ip,"os": item.os[0:6],"status": item.status,"createTime": item.createTime.strftime('%Y-%m-%d %H:%M:%S')} data.append(row) #對最終的資料進行排序 data = sorted(data,key=lambda item: item['createTime']) dataTable['iTotalRecords'] = resultLength # 資料總條數 dataTable['sEcho'] = sEcho + 1 dataTable['iTotalDisplayRecords'] = resultLength # 顯示的條數 dataTable['aaData'] = data return HttpResponse(json.dumps(dataTable,ensure_ascii=False))
最終的表現結果如下圖:
6.新增定時重新整理table的JS
<script> //重新整理方法 function runRefresh() { var interval = setInterval(refreshMonitor,"5000"); } {#定時器執行方法#} function refreshMonitor() { var table = $('#monitorTable').DataTable(); table.ajax.reload(null,false); // 重新整理表格資料,分頁資訊不會重置 } runRefresh(); </script>
最後強調一點,table資料也是可以通過get請求進行載入的。
但是使用了get方式後,在某頁進行操作再進行上面的JS重新整理時會出現行序號紊亂或者分頁資訊被重置的問題。
這也是我碰到的一個坑。
特此記錄一下。
補充知識:關於python的web框架django和Bootstrap-table的使用
這幾天工作中發現要使用到Bootstrap的分頁,django也有分頁,但是當兩者結合起來時發現,是一個強大的分頁。
第一次接觸這兩者,結合起來時踩了不少坑,因為自己是一個python初學者,以前是學的Java,在公司做的python。
自己在網上找到一些資料,但發現這些資料都說的不明白,所以自己也去看了文件。
我把自己的程式碼貼出來吧。
這個方法是將你的資料跟據你的頁碼,頁面大小,分好頁
def page(deploy_list,limit,offset):#查詢分頁,呼叫此方法需要傳獲取的資料列表,頁面大小,頁碼 # 取出該表所有資料 try: paginator = Paginator(deploy_list,limit) # 每頁顯示10條資料 except Exception: print "error" page = int(int(offset) / int(limit) + 1) data=paginator.page(page) response_data = {'total': deploy_list.count(),'rows': []} # 必須帶有rows和total這2個key,total表示總頁數,rows表示每行的內容,這兩個是Bootstrap需要的 return {"data":data,"response_data":response_data}
呼叫上述方法時將自己需要的資料獲取到
def list(request): J_data=page(modename.object.all().values(),request.GET.get("limit"),request.GET.get("offset"))#modelname,這個是你需要查詢的model,modename.object.all().values(),這個可以根據自己的查詢條件去更改,例如:modename.object.filter(username=requset.GET.get("username")).values() for asset in J_data: J_data['response_data']['youmodel ziduan '].append({ "asset_id":asset["asset_id"],"asset_id":asset["asset_id"],}) return HttpResponse(json.dumps(J_data["response_data"])) # 需要json處理下資料格式
前臺程式碼百度很多,可以自己去寫 ,這裡就不再陳述
以上這篇DjangoWeb使用Datatable進行後端分頁的實現就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。