使用场景:不使用Django的模版语言进行分页(网上大多数都使用该方式),使用Jquery DataTable.js 插件进行分页处理。
本人做的是一个表格监控页面,该页面中的table内容每5s刷新一次。
注意:这种方式非长连接(websocket)模式,长连接模式也有弊端,因网络波动导致,倘若一次连接断开,后面将无法继续刷新数据(不重连的话),且比较吃服务器带宽。
故使用Ajax定时刷新获取最新数据,两种方案各有优劣,根据实际场景进行抉择。
代码如下:
1.Html页面内容(本人用的是Admin.lte的前端框架),
引入Datatable css 和 Js,并创建一个table:
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": ''
+ 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 =
'' +
'' +
'' +
'' +
'';
定义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: '',
sWidth: "1%",
data: null,
'render': function (data, type, full, meta) {
return '';
}
},
{title: "名称", data: "name"},
{
title: "IP",
data: "ip",
"render": function (data, type, full, meta) {
var strDelete = '' + data + '';
return strDelete;
}
},
{title: "操作系统", data: "os"},
{title: "状态", data: "status"},
{title: "创建日期", data: "createTime"},
{
data: null,
"render": function (data, type, full, meta) {
var strModify = " ";
var strDelete = " ";
return strModify + strDelete;
}
},
];
上面的列内容中,第1列是隐藏内容,第2列是行序号,第3列check(用来多选的),
第4,6,7,8列是要显示的信息,第5列是超链接。
第9列是操作按钮(根据自己的选择增加、删除)。
一般情况下,上述内容已经够用了。
4.完成表格的初始化:
$("#monitorTable").DataTable(
initDataTable(lengthMenuParam, urlParam, 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
最后强调一点,table数据也是可以通过get请求进行加载的。
但是使用了get方式后,在某页进行操作再进行上面的JS刷新时会出现行序号紊乱或者分页信息被重置的问题。
这也是我碰到的一个坑。
特此记录一下。