Django 自定义分页
自定义分页
pages.py
import copy class Pagination(object): def __init__(self, request, current_page_num, data_obj, per_page_num, pager_count=11): ''' 封装分页相关数据
:param request: 用户请求体对象 :param current_page_num: 当前请求的页码 :param data_obj: 数据库中所查询记录的queryset :param per_page_num: 每页显示的数据条数 :param pager_count: 最多显示的页码个数 ''' # 如果用户请求体中页码为非数字字符则返回第一页的数据 try: current_page_num = int(current_page_num) except ValueError: current_page_num = 1 # 请求页码小于1,返回第一页数据 if current_page_num < 1: current_page_num = 1 self.current_page_num = current_page_num self.data_obj = data_obj self.all_count = data_obj.count() self.per_page_num = per_page_num all_pager, tmp = divmod(self.all_count, per_page_num) if tmp: all_pager += 1 self.all_pager = all_pager self.pager_count = pager_count self.pager_count_half = int((pager_count - 1) / 2) self.request = request @property def start(self): return (self.current_page_num - 1) * self.per_page_num @property def end(self): return self.current_page_num * self.per_page_num # 给每条记录加上page_num编号 def insert_obj_num(self): self.data_obj = self.data_obj[self.start:self.end] page_num = list(range(self.start + 1, self.end + 1)) for i, el in enumerate(self.data_obj): el.page_num = page_num[i] # 保留搜索条件 def get_param(self, page_num): url_param = copy.deepcopy(self.request.GET) url_param['page'] = page_num return url_param.urlencode() # 确定页码的起始位置和结束位置 def page_point(self): # 如果总页码<11个 if self.all_pager <= self.pager_count: page_start = 1 page_end = self.all_pager + 1 else: # 当前页如果<=页面上做多显示11/2个页码 if self.current_page_num <= self.pager_count_half: page_start = 1 page_end = self.pager_count + 1 # 当前页大于5 else: # 页码翻到最后 if (self.current_page_num + self.pager_count_half) > self.all_pager: page_start = self.all_pager - self.pager_count + 1 page_end = self.all_pager + 1 else: page_start = self.current_page_num - self.pager_count_half page_end = self.current_page_num + self.pager_count_half + 1 return page_end, page_start # 返回HTML,返回data数据 def page_html(self): page_end, page_start = self.page_point() page_html_list = [] # 首页 first_page = '<li><a href="?%s">首页</a></li>' % (self.get_param(1),) page_html_list.append(first_page) if self.current_page_num <= 1: prev_page = '<li class="disabled"><a href="#">上一页</a></li>' else: prev_page = '<li><a href="?%s">上一页</a></li>' % (self.get_param(self.current_page_num - 1),) page_html_list.append(prev_page) for i in range(page_start, page_end): if i == self.current_page_num: temp = '<li class="active"><a href="?%s">%s</a></li>' % (self.get_param(i), i) else: temp = '<li><a href="?%s">%s</a></li>' % (self.get_param(i), i,) page_html_list.append(temp) if self.current_page_num >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一页</a></li>' else: next_page = '<li><a href="?%s">下一页</a></li>' % (self.get_param(self.current_page_num + 1),) page_html_list.append(next_page) # 尾页 last_page = '<li><a href="?%s">尾页</a></li>' % (self.get_param(self.all_pager),) page_html_list.append(last_page) self.insert_obj_num() return ''.join(page_html_list), self.data_obj
使用:
views.py
# 查看书籍 def show_book(request): current_page_num = request.GET.get('page', 1) all_book = Book.objects.all() pagination = Pagination(request, current_page_num, all_book, per_page_num=10) page_html, bookdata = pagination.page_html() return render(request, 'show_book.html', locals())
页面渲染:
show_book.html
{% extends 'base.html' %} {% block css %} <link rel="stylesheet" href="/static/css/animate.min.css"> <link rel="stylesheet" href="/static/css/common.css"> {% endblock %} {% block content %} <div class="show_hub"> <a class="flipInX dialog btn btn-primary add_book">添加书籍</a> {% csrf_token %} <div id="HBox" class="animated zoomOut" style="display: none;"> <div class="form-horizontal" style="color: black"> {% csrf_token %} <div class="form-group"> <label for="title" class="col-sm-2 control-label">书籍名称</label> <div class="col-sm-5"> <input type="text" class="form-control" id="title" placeholder="书籍名称" name="title"> </div> </div> <div class="form-group"> <label for="author" class="col-sm-2 control-label">作者</label> <div class="col-sm-5"> <select class="form-control" name="author" id="author" multiple> {% for author in all_author %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <label for="book_type" class="col-sm-2 control-label">书籍类型</label> <div class="col-sm-5"> <select class="form-control" name="book_type" id="book_type" multiple> {% for book_type in all_book_type %} <option value="{{ book_type.pk }}">{{ book_type.btype }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <label for="grade" class="col-sm-2 control-label">评分</label> <div class="col-sm-5"> <input type="text" class="form-control" id="grade" placeholder="评分" name="grade"> </div> </div> <div class="form-group"> <label for="pub_date" class="col-sm-2 control-label">出版日期</label> <div class="col-sm-6"> <input type="date" class="form-control" id="pub_date" placeholder="出版日期" name="pub_date"> </div> </div> <div class="form-group"> <label for="publish" class="col-sm-2 control-label">出版社</label> <div class="col-sm-5"> <select class="form-control" name="publish" id="publish"> {% for publish in all_publish %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <label for="price" class="col-sm-2 control-label">价格</label> <div class="col-sm-5"> <input type="text" class="form-control" id="price" placeholder="价格" name="price"> </div> </div> <div class="form-group"> <div class="col-sm-offset-1 col-sm-10"> <button type="submit" class="btn btn-primary add-book" id="add-book">添加</button> </div> </div> </div> </div> <table class="row table table-hover table-bordered table-striped text-center"> <thead> <tr class="bg-success"> <th class="col-md-1 text-center">编号</th> <th class="col-md-1 text-center">书籍名称</th> <th class="col-md-2 text-center">作者</th> <th class="col-md-1 text-center">书籍类型</th> <th class="col-md-1 text-center">评分</th> <th class="col-md-1 text-center">出版日期</th> <th class="col-md-2 text-center">出版社</th> <th class="col-md-1 text-center">价格</th> <th class="col-md-2 text-center">操作</th> </tr> </thead> <tbody page_id="{{ current_page }}" per_page={{ per_page }}> {% for data in bookdata %} <tr>
<!--记录编号--> <td class="title-id">{{ data.page_num }}</td> <td class="target">{{ data.title }}</td> <td> {% for author in data.authors.all %} <span>{{ author.name }}</span> {% if not forloop.last %} , {% endif %} {% endfor %} </td> <td> {% for book_type in data.book_type.all %} <span>{{ book_type.btype }}</span> {% if not forloop.last %} , {% endif %} {% endfor %} </td> <td>{{ data.grade }}</td> <td>{{ data.pub_date|date:'Y-m-d' }}</td> <td>{{ data.publish.name }}</td> <td>{{ data.price }}</td> <td> <a href="{% url 'edit_book' data.pk %}" class="btn btn-primary btn-sm">编辑</a> <button del_url="{% url 'del_book' data.pk %}" class="btn btn-sm btn-danger del-book">删除 </button> </td> </tr> {% endfor %} </tbody> </table>
<!--分页--> <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> {{ page_html|safe }} </ul> </nav> </div> {% endblock %} {% block js %} <script src="/static/js/book.js"></script> <script src="/static/js/bootstrap.js"></script> <script src="/static/js/jquery.hDialog.min.js"></script> <script> // 弹出层 $('.dialog').hDialog({width: 700, height: 600, modalHide: false, isOverlay: false}); // 获取作者,出版社,书籍类型信息 $('.add_book').click(function () { $('#HBox #title,#price,#grade,#pub_date').val(''); $('#HBox #author,#publish,#book_type').html(''); $.ajax({ url: '/book/add/', type: 'post', data: { 'csrfmiddlewaretoken': $('[name=csrfmiddlewaretoken]').val(), 'type': 'ajax' }, success: function (response) { response = JSON.parse(response); $.each(response, function (i, j) { if ($('#author').attr('id') == i) { $.each(j, function (i, author) { $('#author').append(`<option value='${author.pk}'>${author.name}</option>`) }) } else if ($('#book_type').attr('id') == i) { $.each(j, function (i, book_type) { $('#book_type').append(`<option value='${book_type.pk}'>${book_type.btype}</option>`) }) } else if ($('#publish').attr('id') == i) { $.each(j, function (i, publish) { $('#publish').append(`<option value='${publish.pk}'>${publish.name}</option>`) }) } }) } }) }); // 发送书籍数据 $('#add-book').click(function () { let author = JSON.stringify($('#author').val()); let book_type = JSON.stringify($('#book_type').val()); $.ajax({ url: '/book/add/', type: 'post', data: { csrfmiddlewaretoken: $('[name=csrfmiddlewaretoken]').val(), title: $('#title').val(), author: author, book_type: book_type, grade: $('#grade').val(), pub_date: $('#pub_date').val(), publish: $('#publish').val(), price: $('#price').val(), }, success: function (response) { // response = JSON.parse(response) let book_data = [ 'new', $('#title').val(), $('#author').find("option:selected").text(), $('#book_type').find("option:selected").text(), $('#grade').val(), $('#pub_date').val(), $('#publish').find("option:selected").text(), $('#price').val() ]; let template = $('tr').last().clone(); template.children().slice(0, -1).html(''); template.children().each(function (i, j) { $(this).html(book_data[i]) }); template.children().first().css('color', 'red'); template.children().last().children().last().attr('del_url', `/book/del/${response.pk}/`); template.children().last().children().first().attr('href', `/book/edit/${response.pk}/`); $('tbody').append(template); alert('添加成功'); $('#HBox #title,#price,#grade,#pub_date').val(''); $('#HBox #author,#publish,#book_type').html(''); $('#HBox').css('display', 'None') } }) }); </script> {% endblock %}
Django 分页器
d_pages.py
def page_cut(per_page, book_obj, request): per_page = per_page # 生成分页数据 paginator = Paginator(book_obj, per_page) # 获取客户端上传的页码 page = request.GET.get('page', 1) try: current_page = int(page) # 根据客户端上传的页码,返回对应页码数据 page_data = paginator.page(page) # 捕获页码不是数字的异常,以及强制int失败的异常 except (PageNotAnInteger, ValueError): page_data = paginator.page(1) current_page = 1 # 页码超出范围的异常 except EmptyPage: page_data = paginator.page(paginator.num_pages) current_page = paginator.num_pages # 分页页码 if paginator.num_pages > 11: if current_page - 5 < 1: p_range = range(1, 11) elif current_page + 5 > paginator.num_pages: p_range = range(current_page - 5, paginator.num_pages + 1) else: p_range = range(current_page - 5, current_page + 5) else: p_range = paginator.page_range # 生成每条记录的页码数据 start_page = (current_page - 1) * per_page + 1 end_page = (current_page - 1) * per_page + per_page + 1 page_num = list(range(start_page, end_page)) # 遍历当前页码数据,给每个对象加入页码属性 for i, el in enumerate(page_data): el.pag_num = page_num[i] return {'page_data': page_data, 'paginator': paginator, 'current_page': current_page, 'p_range': p_range, 'per_page': per_page}
使用:
views.py
def show_douban_book(request): # Django 分页器 douban_book_list = DoubanBook.objects.all() result = page_cut(15, douban_book_list, request) return render(request, 'show_douban_book.html', result)
页面渲染
show_doubanbook.html
{% extends 'base.html' %} {% block content %} <div class="show_hub center-block"> <table class="row table table-hover table-bordered table-striped text-center"> <thead> <tr class="bg-success"> <th class="col-md-1">编号</th> <th class="col-md-1">类型</th> <th class="col-md-3">书名</th> <th class="col-md-1">评分</th> <th class="col-md-3">出版信息</th> <th class="col-md-3">操作</th> </tr> </thead> <tbody page_id="{{ current_page }}" per_page={{ per_page }}> {% for data in page_data %} <tr> <td class="title-id">{{ data.pag_num }}</td> <td class="book_type">{{ data.book_type }}</td> <td class="target">{{ data.title }}</td> <td>{{ data.grade }}</td> <td>{{ data.author }}</td> <td> <a href="#" class="btn btn-primary btn-sm">收藏到我的书库</a> <button del_url="{% url 'del_douban_book' data.pk %}" class="btn btn-danger btn-sm del-book"> 删除 </button> </td> </tr> {% endfor %} </tbody> </table> <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> {% if page_data.has_previous %} <li> <a href="?page={{ page_data.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 page_num in p_range %} {% if page_num == current_page %} <li class="active"><a href="?page={{ page_num }}">{{ page_num }}</a></li> {% else %} <li><a href="?page={{ page_num }}">{{ page_num }}</a></li> {% endif %} {% endfor %} {% if page_data.has_next %} <li> <a href="?page={{ page_data.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% else %} <li class="disabled"> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% endif %} </ul> </nav> </div> {% endblock %} {% block js %} <script src="/static/js/book.js"></script> {% endblock %}
自定义分页原版
""" 分页组件使用示例: obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info) page_user_list = USER_LIST[obj.start:obj.end] page_html = obj.page_html() return render(request,'index.html',{'users':page_user_list,'page_html':page_html}) """ class Pagination(object): def __init__(self,current_page_num,all_count,per_page_num=2,pager_count=11): """ 封装分页相关数据 :param current_page: 当前页 :param all_count: 数据库中的数据总条数 :param per_page_num: 每页显示的数据条数 :param pager_count: 最多显示的页码个数 """ try: current_page_num = int(current_page_num) except Exception as e: current_page_num = 1 if current_page_num <1: current_page_num = 1 self.current_page_num = current_page_num self.all_count = all_count self.per_page_num = per_page_num # 总页码 all_pager, tmp = divmod(all_count, per_page_num) if tmp: all_pager += 1 self.all_pager = all_pager self.pager_count = pager_count self.pager_count_half = int((pager_count - 1) / 2) # 5 @property def start(self): return (self.current_page_num - 1) * self.per_page_num @property def end(self): return self.current_page_num * self.per_page_num def page_html(self): # 如果总页码 < 11个: if self.all_pager <= self.pager_count: pager_start = 1 pager_end = self.all_pager + 1 # 总页码 > 11 else: # 当前页如果<=页面上最多显示11/2个页码 if self.current_page_num <= self.pager_count_half: pager_start = 1 pager_end = self.pager_count + 1 # 当前页大于5 else: # 页码翻到最后 if (self.current_page_num + self.pager_count_half) > self.all_pager: pager_start = self.all_pager - self.pager_count + 1 pager_end = self.all_pager + 1 else: pager_start = self.current_page_num - self.pager_count_half pager_end = self.current_page_num + self.pager_count_half + 1 page_html_list = [] first_page = '<li><a href="?page=%s">首页</a></li>' % (1,) page_html_list.append(first_page) if self.current_page_num <= 1: prev_page = '<li class="disabled"><a href="#">上一页</a></li>' else: prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page_num - 1,) page_html_list.append(prev_page) for i in range(pager_start, pager_end): if i == self.current_page_num: temp = '<li class="active"><a href="?page=%s">%s</a></li>' %(i,i) else: temp = '<li><a href="?page=%s">%s</a></li>' % (i,i,) page_html_list.append(temp) if self.current_page_num >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一页</a></li>' else: next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page_num + 1,) page_html_list.append(next_page) last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,) page_html_list.append(last_page) return ''.join(page_html_list)
浙公网安备 33010602011771号