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中的floor()方法
May 15 Python
Python中type的构造函数参数含义说明
Jun 21 Python
Python中字典的setdefault()方法教程
Feb 07 Python
python中MethodType方法介绍与使用示例
Aug 03 Python
python中reduce()函数的使用方法示例
Sep 29 Python
python下载文件记录黑名单的实现代码
Oct 24 Python
python2和python3在处理字符串上的区别详解
May 29 Python
Python flask框架post接口调用示例
Jul 03 Python
python字符串替换re.sub()方法解析
Sep 18 Python
详解Django配置JWT认证方式
May 09 Python
tensorflow中的梯度求解及梯度裁剪操作
May 26 Python
Python机器学习之基于Pytorch实现猫狗分类
Jun 08 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访问MYSQL数据库封装类(附函数说明)
2010/12/04 PHP
PHP中使用file_get_contents post数据代码例子
2015/02/13 PHP
PHP设计模式之装饰者模式代码实例
2015/05/11 PHP
浅析PHP中的闭包和匿名函数
2017/12/25 PHP
Prototype PeriodicalExecuter对象 学习
2009/07/19 Javascript
JavaScript打开word文档的实现代码(c#)
2012/04/16 Javascript
Jquery为a标签的href赋值实现代码
2013/05/03 Javascript
jquery 实现密码框的显示与隐藏示例代码
2013/09/18 Javascript
js文件Cookie存取值示例代码
2014/02/20 Javascript
浅谈jQuery异步对象(XMLHttpRequest)
2014/11/17 Javascript
js方法数据验证的简单实例
2016/09/17 Javascript
jQuery实现动态文字搜索功能
2017/01/05 Javascript
switchery按钮的使用方法
2017/12/18 Javascript
解决jquery的ajax调取后端数据成功却渲染失败的问题
2018/08/08 jQuery
详解vuex的简单todolist例子
2019/07/14 Javascript
JS原型对象操作实例分析
2020/06/06 Javascript
Vue scoped及deep使用方法解析
2020/08/01 Javascript
vue开发chrome插件,实现获取界面数据和保存到数据库功能
2020/12/01 Vue.js
[02:56]《DAC最前线》之国外战队抵达上海备战亚洲邀请赛
2015/01/28 DOTA
[36:05]完美世界DOTA2联赛循环赛 Forest vs DM 第一场 11.06
2020/11/06 DOTA
python 运算符 供重载参考
2009/06/11 Python
python 基础教程之Map使用方法
2017/01/17 Python
在java中如何定义一个抽象属性示例详解
2017/08/18 Python
python shell根据ip获取主机名代码示例
2017/11/25 Python
零基础使用Python读写处理Excel表格的方法
2019/05/02 Python
python实现关闭第三方窗口的方法
2019/06/28 Python
ubuntu 18.04 安装opencv3.4.5的教程(图解)
2019/11/04 Python
python实现一次性封装多条sql语句(begin end)
2020/06/06 Python
Tensorflow中批量读取数据的案列分析及TFRecord文件的打包与读取
2020/06/30 Python
keras 两种训练模型方式详解fit和fit_generator(节省内存)
2020/07/03 Python
PyQt5通过信号实现MVC的示例
2021/02/06 Python
python源文件的字符编码知识点详解
2021/03/04 Python
美国美食礼品篮网站:Gourmet Gift Baskets
2019/12/15 全球购物
采购员岗位职责范本
2015/04/07 职场文书
有关水浒传的读书笔记
2015/06/25 职场文书
2016年国陪研修感言
2015/11/18 职场文书