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中用于返回绝对值的abs()方法
May 14 Python
用不到50行的Python代码构建最小的区块链
Nov 16 Python
Python3之文件读写操作的实例讲解
Jan 23 Python
python中copy()与deepcopy()的区别小结
Aug 03 Python
python自动化生成IOS的图标
Nov 13 Python
Flask核心机制之上下文源码剖析
Dec 25 Python
Python 多维List创建的问题小结
Jan 18 Python
使用Python向DataFrame中指定位置添加一列或多列的方法
Jan 29 Python
python实现通过flask和前端进行数据收发
Aug 22 Python
Python Pickle 实现在同一个文件中序列化多个对象
Dec 30 Python
python基本算法之实现归并排序(Merge sort)
Sep 01 Python
python爬虫如何解决图片验证码
Feb 14 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
再说下636单管机
2021/03/02 无线电
laravel中命名路由的使用方法
2017/02/24 PHP
PHP 二维array转换json的实例讲解
2018/08/21 PHP
javascript js cookie的存储,获取和删除
2007/12/29 Javascript
利用Ext Js生成动态树实例代码
2008/09/08 Javascript
ext 同步和异步示例代码
2009/09/18 Javascript
JavaScript去掉空格的方法集合
2010/12/28 Javascript
JS获取农历日期具体实例
2013/11/14 Javascript
jquery实现从数组移除指定的值
2015/06/24 Javascript
JavaScript实现图片轮播的方法
2015/07/31 Javascript
javascript实现checkbox复选框实例代码
2016/01/10 Javascript
jquery仿QQ登录账号选择下拉框效果
2016/03/22 Javascript
JS实现一个简单的日历
2017/02/22 Javascript
Vue监听数据渲染DOM完以后执行某个函数详解
2018/09/11 Javascript
微信小程序常用的3种提示弹窗实现详解
2019/09/19 Javascript
详解钉钉小程序组件之自定义模态框(弹窗封装实现)
2020/03/07 Javascript
Vue看了就会的8个小技巧
2021/01/21 Vue.js
python生成词云的实现方法(推荐)
2017/06/13 Python
django 发送手机验证码的示例代码
2018/04/25 Python
在Pandas中DataFrame数据合并,连接(concat,merge,join)的实例
2019/01/29 Python
详解Python3除法之真除法、截断除法和下取整对比
2019/05/23 Python
梅尔倒谱系数(MFCC)实现
2019/06/19 Python
python保留小数位的三种实现方法
2020/01/07 Python
利用python控制Autocad:pyautocad方式
2020/06/01 Python
详解Python利用configparser对配置文件进行读写操作
2020/11/03 Python
巧克力领导品牌瑞士莲美国官网:Lindt Chocolate美国
2016/08/25 全球购物
李维斯德国官方网上商店:Levi’s德国
2016/09/10 全球购物
美国专注于健康商品的网站:eVitamins
2017/01/23 全球购物
匡威德国官网:Converse德国
2019/01/26 全球购物
美国牙科折扣计划:DentalPlans.com
2019/08/26 全球购物
Lovedrobe官网:英国领先的大码服装品牌
2019/09/19 全球购物
奥林匹亚体育:Olympia Sports
2020/12/30 全球购物
新春寄语大全
2014/04/09 职场文书
毕业实习指导教师评语
2014/12/31 职场文书
JS实现简单控制视频播放倍速的实例代码
2021/04/18 Javascript
Django对接elasticsearch实现全文检索的示例代码
2021/08/02 Python