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 相关文章推荐
Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程
Nov 18 Python
使用Python的Twisted框架实现一个简单的服务器
Apr 16 Python
解决Python requests 报错方法集锦
Mar 19 Python
分析Python中解析构建数据知识
Jan 20 Python
Python正则匹配判断手机号是否合法的方法
Dec 09 Python
对python操作kafka写入json数据的简单demo分享
Dec 27 Python
Python lxml解析HTML并用xpath获取元素的方法
Jan 02 Python
实时获取Python的print输出流方法
Jan 07 Python
对python判断ip是否可达的实例详解
Jan 31 Python
django-crontab 定时执行任务方法的实现
Sep 06 Python
关于numpy中eye和identity的区别详解
Nov 29 Python
彻底搞懂python 迭代器和生成器
Sep 07 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
使用PHP获取当前url路径的函数以及服务器变量
2013/06/29 PHP
php简单分页类实现方法
2015/02/26 PHP
php实现阳历阴历互转的方法
2015/10/28 PHP
Laravel如何使用Redis共享Session
2018/02/23 PHP
微信公众平台开发教程⑤ 微信扫码支付模式介绍
2019/04/10 PHP
让您的菜单不离网站
2006/10/03 Javascript
javascript中声明函数的方法及调用函数的返回值
2014/07/22 Javascript
JavaScript动态创建link标签到head里的方法
2014/12/22 Javascript
jquery获取img的src值的简单实例
2016/05/17 Javascript
微信小程序实现动态设置placeholder提示文字及按钮选中/取消状态的方法
2017/12/14 Javascript
使用mock.js随机数据和使用express输出json接口的实现方法
2018/01/07 Javascript
详解webpack 入门与解析
2018/04/09 Javascript
使用React手写一个对话框或模态框的方法示例
2019/04/25 Javascript
JavaScript生成随机验证码代码实例
2019/09/28 Javascript
vue组件 keep-alive 和 transition 使用详解
2019/10/11 Javascript
Vue快速实现通用表单验证的方法
2020/02/24 Javascript
vue render函数动态加载img的src路径操作
2020/10/26 Javascript
[00:37]DOTA2上海特级锦标赛 OG战队宣传片
2016/03/03 DOTA
六个窍门助你提高Python运行效率
2015/06/09 Python
Python 将RGB图像转换为Pytho灰度图像的实例
2017/11/14 Python
Python基于列表list实现的CRUD操作功能示例
2018/01/05 Python
利用python如何处理nc数据详解
2018/05/23 Python
Python使用爬虫爬取静态网页图片的方法详解
2018/06/05 Python
python多进程读图提取特征存npy
2019/05/21 Python
在linux系统下安装python librtmp包的实现方法
2019/07/22 Python
python实现本地批量ping多个IP的方法示例
2019/08/07 Python
Python利用matplotlib绘制散点图的新手教程
2020/11/05 Python
公关关系专员的自我评价分享
2013/11/20 职场文书
建筑装饰学院室内设计专业个人自我评价
2013/12/07 职场文书
优秀演讲稿范文
2013/12/29 职场文书
高中同学聚会邀请函
2014/01/11 职场文书
承认错误的检讨书
2014/01/30 职场文书
安全生产先进个人材料
2014/02/06 职场文书
奥林匹克运动会口号
2014/06/19 职场文书
单位未婚证明范本
2014/11/25 职场文书
祝福语集锦:朋友新店开业祝福语
2019/12/10 职场文书