DjangoWeb使用Datatable进行后端分页

使用场景:不使用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' %}">
<link rel="stylesheet" href="{% static  '/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css' %}">

<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 + '" 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))

最终的表现结果如下图:


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刷新时会出现行序号紊乱或者分页信息被重置的问题。

这也是我碰到的一个坑。

特此记录一下。


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值