使用场景:不使用Django的模版语言进行分页(网上大多数都使用该方式),使用Jquery DataTable.js 插件进行分页处理。
本人做的是一个表格监控页面,该页面中的table内容每5s刷新一次。
注意:这种方式非长连接(websocket)模式,长连接模式也有弊端,因网络波动导致,倘若一次连接断开,后面将无法继续刷新数据(不重连的话),且比较吃服务器带宽。
故使用Ajax定时刷新获取最新数据,两种方案各有优劣,根据实际场景进行抉择。
代码如下:
1.Html页面内容(本人用的是Admin.lte的前端框架),
引入Datatable css 和 Js,并创建一个table:
1
2
3
4
5
6
7
|
<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这个属性很重要,这个属性能很友好的提醒用户数据正在读取中,因为读取服务器数据是要时间的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
/ / 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,
}
}
|
定义左侧显示参数:
1
2
3
4
5
6
|
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' %}";
定义列内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
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">' ,
sWidth: "1%" ,
data: null,
'render' : function (data, type , full, meta) {
return '<div><input type="checkbox"></div>' ;
}
},
{title: "名称" , data: "name" },
{
title: "IP" ,
data: "ip" ,
"render" : function (data, type , full, 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" },
{
data: null,
"render" : function (data, type , full, 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.完成表格的初始化:
1
2
3
|
$( "#monitorTable" ).DataTable(
initDataTable(lengthMenuParam, urlParam, columnsParam)
)
|
注意,我这里的datatable分页使用的是post请求, 因为分页的时候需要向服务端传递很多参数,使用get请求的话,这里就很难受了。
5.服务端代码,返回结果的内容格式是固定的,不要想着去修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
@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
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<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。
自己在网上找到一些资料,但发现这些资料都说的不明白,所以自己也去看了文档。
我把自己的代码贴出来吧。
这个方法是将你的数据跟据你的页码,页面大小,分好页
1
2
3
4
5
6
7
8
9
10
|
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}
|
调用上述方法时将自己需要的数据获取到
1
2
3
4
5
6
7
|
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进行后端分页的实现就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u012605477/article/details/80605784