DjangoWeb使用Datatable进行后端分页的实现


Posted in Python onMay 18, 2020

使用场景:不使用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">',
     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.完成表格的初始化:

$("#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))

最终的表现结果如下图:

DjangoWeb使用Datatable进行后端分页的实现

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进行后端分页的实现

以上这篇DjangoWeb使用Datatable进行后端分页的实现就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中Django 后台自定义表单控件
Mar 28 Python
利用Python+Java调用Shell脚本时的死锁陷阱详解
Jan 24 Python
windows下python和pip安装教程
May 25 Python
django manage.py扩展自定义命令方法
May 27 Python
python通过tcp发送xml报文的方法
Dec 28 Python
Django 日志配置按日期滚动的方法
Jan 31 Python
使用turtle绘制五角星、分形树
Oct 06 Python
Python 实现OpenCV格式和PIL.Image格式互转
Jan 09 Python
python读取dicom图像示例(SimpleITK和dicom包实现)
Jan 16 Python
利用python中集合的唯一性实现去重
Feb 11 Python
Python 面向对象静态方法、类方法、属性方法知识点小结
Mar 09 Python
如何使用python的ctypes调用医保中心的dll动态库下载医保中心的账单
May 24 Python
django-orm F对象的使用 按照两个字段的和,乘积排序实例
May 18 #Python
PyTorch中torch.tensor与torch.Tensor的区别详解
May 18 #Python
django queryset相加和筛选教程
May 18 #Python
python中JWT用户认证的实现
May 18 #Python
python 实现读取csv数据,分类求和 再写进 csv
May 18 #Python
python 实现分组求和与分组累加求和代码
May 18 #Python
Django ORM实现按天获取数据去重求和例子
May 18 #Python
You might like
探讨:parse url解析URL,返回其组成部分
2013/06/14 PHP
phpstrom使用xdebug配置方法
2013/12/17 PHP
关于php几种字符串连接的效率比较(详解)
2017/02/22 PHP
Yii2 批量插入、更新数据实例
2017/03/15 PHP
JS启动应用程序的一个简单例子
2008/05/11 Javascript
一个小型js框架myJSFrame附API使用帮助
2008/06/28 Javascript
jQuery渐变发光导航菜单的实例代码
2013/03/27 Javascript
解析Jquery中如何把一段html代码动态写入到DIV中(实例说明)
2013/07/09 Javascript
JavaScript执行顺序详细介绍
2013/12/04 Javascript
js中for in的用法示例解析
2013/12/25 Javascript
JavaScript Math 对象常用方法总结
2016/04/28 Javascript
Angular2从搭建环境到开发步骤详解
2016/10/17 Javascript
jQuery grep()方法详解及实例代码
2016/10/30 Javascript
微信小程序表单验证功能完整实例
2017/12/01 Javascript
微信小程序实现红包功能(后端PHP实现逻辑)
2018/07/11 Javascript
node.js读取Excel数据(下载图片)的方法示例
2018/08/02 Javascript
layui 表格的属性的显示转换方法
2018/08/14 Javascript
nodejs遍历文件夹下并操作HTML/CSS/JS/PNG/JPG的方法
2018/11/01 NodeJs
JavaScript 正则应用详解【模式、欲查、反向引用等】
2020/05/13 Javascript
JavaScript使用prototype属性实现继承操作示例
2020/05/22 Javascript
Python转换HTML到Text纯文本的方法
2015/01/15 Python
Python3 适合初学者学习的银行账户登录系统实例
2017/08/08 Python
python使用matplotlib库生成随机漫步图
2018/08/27 Python
在python中利用KNN实现对iris进行分类的方法
2018/12/11 Python
解决在pycharm中显示额外的 figure 窗口问题
2019/01/15 Python
python xlwt如何设置单元格的自定义背景颜色
2019/09/03 Python
Python AutoCAD 系统设置的实现方法
2020/04/01 Python
Python reversed反转序列并生成可迭代对象
2020/10/22 Python
python将YUV420P文件转PNG图片格式的两种方法
2021/01/22 Python
Blancsom美国/加拿大:服装和生活用品供应商
2018/07/27 全球购物
迪卡侬(Decathlon)加拿大官网:源自法国的运动专业超市
2020/11/22 全球购物
介绍一下Java的事务处理
2012/12/07 面试题
优秀干部获奖感言
2014/01/31 职场文书
财务人员担保书
2014/05/13 职场文书
win10键盘驱动怎么修复?Win10键盘驱动修复小技巧
2022/04/06 数码科技
Python使用Opencv打开笔记本电脑摄像头报错解问题及解决
2022/06/21 Python