Django中如何灵活使用前端分页和后台分页
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Django中如何灵活使⽤前端分页和后台分页
我们在遇到数据展⽰的时候,避免不了分页展⽰或者是懒加载(lazy的介绍后续更新)
每次做分页的时候,我们就⾯临着两种选择,前端做到分页效果,另外⼀种就是后端动态(Django⾃带的分页模块 paginator)做成分页效果;
这两种⽅式各有利弊,前端做的分页效果,在点击切换页⾯的时候速度⽐较快,原因是前端做的分页效果,是预先把所有数据加载完之后,再通过jQuery 的插件dataTable 动态将页⾯做成分页的效果;适⽤于少量的数据。
通过Django 后端做出来的分页效果,是通过Django⾃带的分页模块,将查询结果分为多份,提⾼⽤户体验。
适⽤于⼤量数据查询。
前端分页
前端分页主要⽤到的 jquery 中的dataTable 插件
<script>
$(document).ready(function () {
$('#dt_list').DataTable({
"autoWidth": true,
"searching": false,
"paging": false,
"ordering": true,
"info": false,
"scrollX": false,
'columnDefs':[
{
'render': function(data, type, row){
return '<a href="' + row[0] + '">' + data + '</a>';
},
'targets': [1]
},
{'visible': false, 'targets':[0]}
]
});
});
下边是 datatable 的⼀些参数说明:
$(function () {
$("#table1").DataTable({
// 是否允许检索
"searching": false,
// 是否允许排序
"ordering": true,
// 初期排序列
//"order": [[0,'asc'],[1,'desc']],
// 是否显⽰情报就是"当前显⽰1/100记录"这个信息
"info": false,
// 是否允许翻页,设成false,翻页按钮不显⽰
"paging": false,
// ⽔平滚动条
"scrollX": false,
// 垂直滚动条
"scrollY": false,
// 件数选择功能默认true
"lengthChange": false,
// 件数选择下拉框内容
"lengthMenu": [10, 25, 50, 75, 100],
// 每页的初期件数⽤户可以操作lengthMenu上的值覆盖
"pageLength": 50,
//翻页按钮样式
// numbers:数字
// simple:前⼀页,后⼀页
// simple_numbers:前⼀页,后⼀页,数字
// full:第⼀页,前⼀页,后⼀页,最后页
//full_numbers:第⼀页,前⼀页,后⼀页,最后页,数字
//first_last_numbers:第⼀页,最后页,数字
"pagingType": "full_numbers",
// ⾏样式应⽤指定多个的话,第⼀⾏tr的class为strip1,第⼆⾏为strip2,第三⾏为strip3.
// 第四⾏以后⼜开始从strip1循环。
如果想指定成斑马条状,这⾥的class必须指定为2个。
"stripeClasses": ['strip1', 'strip2', 'strip3'],
// ⾃动列宽
"autoWidth": true,
// 是否表⽰ "processing" 加载中的信息,这个信息可以修改
"processing": true,
// 每次创建是否销毁以前的DataTable,默认false
"destroy": false,
// 控制表格各种信息的表⽰位置(⽐较复杂)默认:lfrtip
// 具体参考:https:///reference/option/dom
"dom": 'lrtip',
"language": {
"processing": "DataTables is currently busy",
// 当前页显⽰多少条
"lengthMenu": "Display _MENU_ records",
// _START_(当前页的第⼀条的序号) ,_END_(当前页的最后⼀条的序号),_TOTAL_(筛选后的总件数), // _MAX_(总件数),_PAGE_(当前页号),_PAGES_(总页数)
"info": "Showing page _PAGE_ of _PAGES_",
// 没有数据的显⽰(可选),如果没指定,会⽤zeroRecords的内容
"emptyTable": "No data available in table",
// 筛选后,没有数据的表⽰信息,注意emptyTable优先级更⾼
"zeroRecords": "No records to display",
// 千分位的符号,只对显⽰有效,默认就是"," ⼀般不要改写
//"thousands": "'",
// ⼩数点位的符号,对输⼊解析有影响,默认就是"." ⼀般不要改写
//"decimal": "-",
// 翻页按钮⽂字控制
"paginate": {
"first": "First page",
"last": "Last page",
"next": "Next page",
"previous": "Previous page"
},
// Client-Side⽤,Server-Side不⽤这个属性
"loadingRecords": "Please wait - loading..."
},
// 默认是false
// 如果设为true,将只渲染当前也的html,速度会很快,但是通过API就访问不到所有页的数据,有利有弊
//"deferRender": false,
// 服务器端处理⽅式
"serverSide": true,
// ajax选项可以直接简单指定成请求的⽂件
//"ajax": "data.json",
// 也可以⽤对象来配置,更加灵活
"ajax": {
// url可以直接指定远程的json⽂件,或是MVC的请求地址 /Controller/Action
url: "data.json",
type: 'POST',
// 传给服务器的数据,可以添加我们⾃⼰的查询参数
data: function (param) {
param.opportunityNO = $('#txtSearch').val();
return param;
},
//⽤于处理服务器端返回的数据。
dataSrc是DataTable特有的
dataSrc: function (myJson) {
if (myJson.timeout) {
return "";
}
return myJson;
}
},
//指定⽤于⾏ID的属性名默认是:DT_RowId
"rowId": 'staffId',
// 列定义
"columns": [
{
// data 可以是属性名,或嵌套属性(WORKTM1.ID),数组ArrOne[,] ⽤中括号中的字符连接数组后返回。
"data": "WORKTM1",
// 这⾥的class会应⽤到td上⾯
"className": "dt-body-right",
// 列宽
"width": 40,
// 很灵活,描绘每个单元格
// data:当前cell的data,这个data和type有关
// type:filter,display,type,sort
// row:当前⾏数据
// https:///reference/option/columns.render
"render": function (data, type, row, meta) {
return type === 'display' && data.length > 40 ?
'<span title="' + data + '">' + data.substr(0, 38) + '...</span>' : data;
},
// 是否可排序默认值:true
"orderable": true,
// 指定当前列排序操作的时候,⽤哪⼀列(⼏列)的数据进⾏真正的排序(通常是隐藏的)
"orderData": [0, 1],
// 这个属性和type属性相似,指定排序时候这⼀列该怎么转换数据,
//需要⽤到其他的插件详细: https:///plug-ins/sorting/
"orderDataType": "dom-text",
// 是否显⽰当前列默认值:true
"visible": false,
// 是否允许搜索此列默认值:true
"searchable": false,
//这个属性仅Client-Side有效, Server-Side在服务器端排序
//主要⽤于排序和筛选,指定当前列作为什么类型进⾏解析
//内置值:date,num,num-fmt,html-num,html-num-fmt,html,string
// 还可以⽤其他插件提供的类型:详细: https:///plug-ins/sorting/
// 有html开头的,都会讲html标签先移除后进⾏数据处理
"type": "html",
// 列头⽂字,如果没有指定thead,则会⽣成。
如何指定了thead,则会覆盖当前列头⽂字
"title": "My column title",
// defaultContent:默认值,属性值为null或undefined就会⽤这个值
"defaultContent": "<i>Not set</i>",
// 单元格类型:"th","td"
"cellType" : "td",
// 单元格创建完后的回调,可以作为render的补充
// cell:TD的dom
// cellData:原始的单元格数据,如何render中进⾏了格式化,⽤$(cell).html()来取格式化后的数据
// rowData:⾏数据
// row:⾏号
// col:列号
"createdCell": function (cell, cellData, rowData, row, col) {
if ( cellData < 1 ) {
$(td).css('color', 'red')
}
}
},
{ "data": "WORKTM2", "className": "dt-body-right", "width": 40 },
{ "data": "WORKTM3", "className": "dt-body-right", "width": 40 },
{ "data": "WORKTM4", "className": "dt-body-right", "width": 40 },
{ "data": "RESTDAY1", "className": "dt-body-right", "width": 40 },
{ "data": "RESTDAY2", "className": "dt-body-right", "width": 40 },
{ "data": "RESTDAY3", "className": "dt-body-right", "width": 40 },
{ "data": "RESTDAY4", "className": "dt-body-right", "width": 40 },
{ "data": "RESTDAY5", "className": "dt-body-right", "width": 40 }
],
// 和上⾯的columns类似,columns可以定义的属性,都可以在这⾥定义,
// 另外增加targets属性⽤于指定列范围(可以多列)
// 优先级:上⾯的columns⾼于columnDefs
columnDefs: [
{
targets: [0, 2],
render: function (data, type, row, meta) {
if (type === 'display') {
var ctemp = $(".dayinfo").children().eq(meta.col).attr("class");
var cname = ctemp ? ctemp : "";
var readonly = $(".dayinfo").children().eq(meta.col).attr("data-fixed") == "fixed" ? "readonly" : "";
return '<input type="input" class="form-control dt-body-center ' + cname + '" ' + readonly + ' value="' + data + '">'; }
return data;
},
}],
// 每⼀⾏创建完调⽤的函数
"createdRow": function (row, data, dataIndex) {
// row : tr dom
// data: row data
// dataIndex:row data's index
if (data[4] == "A") {
$(row).addClass('important');
}
},
// 每⼀⾏被创建,但还没有被加载到document中,这个函数优先于createdRow
// 个⼈觉得⽤createdRow更好
"rowCallback": function (row, data, index) {
// row : tr dom
// data: row data
// index:row data's index
if ( data[4] == "A" ) {
$('td:eq(4)', row).html( '<b>A</b>' );
}
},
//thead被描画后调⽤
"headerCallback": function (thead, data, start, end, display) {
//thead:dom, data:原始的datatable数据,display:当前显⽰排序好的datatable数据(有可能经过排序)
// start end :当前dispaly数据的开始结束序号
$(thead).find('th').eq(0).html( 'Displaying '+(end-start)+' records' );
},
// tfoot被描画后调⽤,通常可⽤于计算合计值
"footerCallback": function (tfoot, data, start, end, display) {
//tfoot:dom, data:原始的datatable数据,display:当前显⽰排序好的datatable数据(有可能经过排序) // start end :当前dispaly数据的开始结束序号
var api = this.api();
$( api.column( 5 ).footer() ).html(
api.column( 5 ).data().reduce( function ( a, b ) {
return a + b;
}, 0 )
);
},
// 初始化,描画都已经完成,常⽤于ajax
"initComplete": function( settings, json ) {
$('div.loading').remove();
},
// 每次DataTable描画后都要调⽤,调⽤这个函数时,table可能没有描画完成,
// 所以不要在⾥⾯操作table的dom,要操作dom应放在initComplete
"drawCallback": function( settings ) {
var api = this.api();
// Output the data for the visible rows to the browser's console
console.log( api.rows( {page:'current'} ).data() );
},
// 这个函数可以改写数字的格式化⽅式
// 默认DataTable⽤ language.thousands来解析数字,“,”
"formatNumber": function ( toFormat ) {
return toFormat.toString().replace(
/\B(?=(\d{3})+(?!\d))/g, "'"
);
}
});
});
Django 后端分页
导⼊分页模块
from django.core.paginator import Paginator
查询所有数据列表queryset对象
book_list = BorrotBook.objects.all()
实例化对象
paginator = Paginator(book_list, 10)
Paginator类对象的属性
序号属性名说明
1num_pages返回分页之后的总页数
2page_range返回分页后的页码列表
Paginator类对象的⽅法
序号⽅法名说明
1page(self, number)返回第number页的page类实例对象
Page实例对象的属性
序号属性名说明
1number返回当前页的页码
2object_list返回当前页的数据查询集
3paginator返回对应的Paginator类对象
page实例对象的⽅法
序号⽅法名说明
1has_previous判断当前页是否有前⼀页
2has_next判断当前页是否有下⼀页
3previous_page_number返回前⼀页的页码
4next_page_number返回下⼀页的页码
按钮前端代码参考:
<nav aria-label="Page navigation" style="color:red; text-align: center">
<ul class="pagination">
<li ><a href="?page=1" aria-label="Previous"><span aria-hidden="true">⾸页</span></a></li>
{% if current_page.has_previous %}
<li><a href="?page={{ current_page.previous_page_number }}" aria-label="Previous"><span aria-hidden="true">上⼀页</span></a></li> {% else %}
<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">上⼀页</span></a></li>
{% endif %}
{% for item in page_range %}
{% if current_num == item %}
<li class="active"><a href="?page={{ item }}">{{ item }}</a></li>
{% else %}
<li><a href="?page={{ item }}">{{ item }}</a></li>
{% endif %}
{% endfor %}
{% if current_page.has_next %}
<li><a href="?page={{ current_page.next_page_number }}" aria-label="Next"><span
aria-hidden="true">下⼀页</span></a></li>
{% else %}
<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">下⼀页</span></a></li>
{% endif %}
<li><a href="?page={{paginator_num_pages}}" aria-label="Previous"><span aria-hidden="true">尾页</span></a></li>
</ul>
</nav>
后端与前端交互的时候,需要给前端返回: paginator 对象,查询当前页对象,页码列表。