作者:HelloGitHub-追梦人物

文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库

通过 Django Pagination 实现简单分页 中,我们实现了一个简单的分页导航。但效果有点差强人意,我们只能点上一页和下一页的按钮进行翻页。比较完善的分页效果应该像下面这样,但想实现这样一种效果,Django Pagination 内置的 API 已无能为力。接下来我们将通过拓展 Django Pagination 来实现下图这样比较完善的分页效果。

分页效果概述

一个比较完善的分页效果应该具有以下特性,就像上图展示的那样,很多网站都采用了类似这种的分页导航方式。

  • 始终显示第一页和最后一页。
  • 当前页码高亮显示。
  • 显示当前页码前后几个连续的页码。
  • 如果两个页码号间还有其它页码,中间显示省略号以提示用户。

分页思路

如果需要自己来实现分页效果,我们会怎么做呢?先来分析一下导航条的组成部分,可以看到整个分页导航条其实可以分成 7 个部分:

  1. 第 1 页页码,这一页需要始终显示。
  2. 第 1 页页码后面的省略号部分。但要注意如果第 1 页的页码号后面紧跟着页码号 2,那么省略号就不应该显示。
  3. 当前页码的左边部分,比如这里的 3-4。
  4. 当前页码,比如这里的 5。
  5. 当前页码的右边部分,比如这里的 6-7。
  6. 最后一页页码前面的省略号部分。但要注意如果最后一页的页码号前面跟着的页码号是连续的,那么省略号就不应该显示。
  7. 最后一页的页码号。

因此我们的思路是,在视图中依据上述规则生成页码列表,然后在模板中循环显示页码列表就可以了。有了思路,实现起来其实也并不很难。不过对于这类常见需求,别人早就帮我们实现好了,本着不重复造轮子的原则,直接拿来用就好。

第一个 Django 第三方拓展:django-pure-pagination

我们第一次开始接触 django 第三方拓展,在此之前我们一直都基于 django 本身我们提供的功能在开发,然而 django 强大的地方就在于海量的第三方应用供我们挑选,几乎大部分 web 开发中的需求,django 都能找到他人已经写好的第三方应用,拿来即用。

事实上,正确的 django 开发姿势应该是这样的:

  1. 充分理解你的需求,想一想,如果自己实现,我会怎么做?
  2. 通过 Google、GitHub、开发者社区论坛等调研已有的实现类似需求的应用
  3. 拿来即用,并尝试理解他人是如何实现这个功能的

以我们的分页功能举例:

首先我们上面分析了分页需求的实现。然后我在 GitHub 上通过 django pagination 关键词进行搜索,在比较了多个 star 数比较高的项目后,发现 django-pure-pagination 文档最清晰,使用最简单,因此决定将这个应用集成到我们的博客来。值得一提的是,尽管这个应用显示作者最后一次更新代码在 4 年前,但我粗略浏览了一下源码,发现其依赖的 django api 4 年来异常稳定,所以确保能在 django 2.2 中使用。

接下来我们就来使用它,首先安装它:

$ pipenv install django-pure-pagination

然后将它注册到 INSTALLED_APPS 里:

INSTALLED_APPS = [
# ...
'pure_pagination', # 分页 'blog.apps.BlogConfig', # 注册 blog 应用
'comments.apps.CommentsConfig', # 注册 comments 应用
]

修改一下 IndexView,让它继承 django-pure-pagination 提供的 PaginationMixin,这个混入类将为我们提供上述提到的分页功能。

class IndexView(PaginationMixin, ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'post_list'
paginate_by = 10

然后我们可以在 common.py 配置中配置一下分页的效果,这是 django-pure-pagination 提供的配置项,用于个性化配置分页效果:

# django-pure-pagination 分页设置
PAGINATION_SETTINGS = {
'PAGE_RANGE_DISPLAYED': 4, # 分页条当前页前后应该显示的总页数(两边均匀分布,因此要设置为偶数),
'MARGIN_PAGES_DISPLAYED': 2, # 分页条开头和结尾显示的页数
'SHOW_FIRST_PAGE_WHEN_INVALID': True, # 当请求了不存在页,显示第一页
}

在模板中需要分页的地方,调用分页对象的 render 方法就可以了,比如在 index.html 中:

{% if is_paginated %}
{{ page_obj.render }}
{% endif %}

注意这里 page_obj 是分页后的对象列表,具体请参考上一篇文章的讲解。render 方法会自动帮我们渲染一个预先定义好的分页条,至此,分页功能就完成了。

自定义模板

有时候预定义的分页条并不能满足我们的需求,我们可以通过自定义的模板来覆盖预定义的模板。django 查找模板的顺序是,首先在项目配置的模板根路径寻找(我们项目中配的是 templates 文件夹),没有找到的话,再去应用的 templates 目录下寻找。分页模板预定义的路径为 pure_pagination/pagination.html,所以我们可以在项目模板根路径下建立一个一模一样的文件结构,这样 django 就会首先找到我们的模板,从而应用我们自定义的模板,而不是预定义的模板。

在 templates 目录下新建一个 pure_pagination\ 目录,然后建立一个 pagination.html 文件。

接下来便是在模板中设置分页导航了,将导航条的七个部分的数据一一展现即可,示例代码如下:

<div class="text-center pagination" style="width: 100%">
<ul>
{% if page_obj.has_previous %}
<li><a href="?{{ page_obj.previous_page_number.querystring }}"
class="prev">&lsaquo;&lsaquo; </a></li>
{% else %}
<li><span class="disabled prev">&lsaquo;&lsaquo; </span></li>
{% endif %}
{% for page in page_obj.pages %}
{% if page %}
{% ifequal page page_obj.number %}
<li class="current"><a href="#">{{ page }}</a></li>
{% else %}
<li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
{% endifequal %}
{% else %}
...
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li><a href="?{{ page_obj.next_page_number.querystring }}" class="next"> &rsaquo;&rsaquo;</a>
</li>
{% else %}
<li><span class="disabled next"> &rsaquo;&rsaquo;</span></li>
{% endif %}
</ul>
</div>

多添加几篇文章,在示例中就可以看到分页效果了。要使分页导航更加美观,通过设置其 CSS 样式即可。


『讲解开源项目系列』——让对开源项目感兴趣的人不再畏惧、让开源项目的发起者不再孤单。跟着我们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系我们、加入我们,让更多人爱上开源、贡献开源~

稳定易用的 Django 分页库,完善分页功能的更多相关文章

  1. python 学习笔记十八 django深入学习三 分页,自定义标签,权限机制

    django  Pagination(分页) django 自带的分页功能非常强大,我们来看一个简单的练习示例: #导入Paginator>>> from django.core.p ...

  2. 26.Django模板语言和分页

    继承 extends 子版只能继承一个父模板 1.父模板 master.html <!DOCTYPE html> <html lang="en"> < ...

  3. 4.Django模板语言和分页

    继承 extends 子版只能继承一个父模板 1.父模板 master.html <!DOCTYPE html> <html lang="en"> < ...

  4. meteor中分页库alethes:pages用法汇总

    1.添加分页库: meteor add alethes:pages 2.新建分页: Pages = new Meteor.Pagination("collection-name") ...

  5. Django的rest_framework的分页组件源码分析

    前言: 分页大家应该都很清楚,今天我来给大家做一下Django的rest_framework的分页组件的分析:我的讲解的思路是这样的,分别使用APIview的视图类和基于ModelViewSet的视图 ...

  6. python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)

    一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...

  7. [django]drf知识点梳理-分页

    msyql分页 limit offset https://www.cnblogs.com/iiiiiher/articles/8846194.html django自己实现分页 https://www ...

  8. django项目一 分页器(前端分页和后端分页区别)

    1. 客户信息展示 1. 母版和继承 {% extends 'layout'%} {% load static%} {% static '文件路径' %} block css js content 2 ...

  9. Django Rest framework 之 分页

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

随机推荐

  1. Condition对象以及ArrayBlockingQueue阻塞队列的实现(使用Condition在队满时让生产者线程等待, 在队空时让消费者线程等待)

    Condition对象 一).Condition的定义 Condition对象:与锁关联,协调多线程间的复杂协作. 获取与锁绑定的Condition对象: Lock lock = new Reentr ...

  2. python容器类型元组的操作

    元组:使用小括号进行表示一组元素,其元素与元素之间使用逗号隔开:注意:元组的的值是不可修改的: 1.元组值得增加:元组是不可以直接增加值的,但是可以通过+进行拼接 # 声明一个元组: tuple1 = ...

  3. Linux 命令记录

    记录Linux下使用过的命令: Linux端 1.测试当前系统支持语言(我这用的是xshell,如果出现乱码,则在file-properties-terminal-encoding中,设置为utf-8 ...

  4. nginx支持wss配置

    nginx证书 nginx.conf配置

  5. 【论文阅读】CornerNet: Detecting Objects as Paired Keypoints

    以下内容将介绍ECCV2018的一篇目标检测的文章<CornerNet: Detecting Objects as Paired Keypoints>.该文章讲述了一个老子就是不用anch ...

  6. MySql分库分表与分区的区别和思考

    一.分分合合 说过很多次,不要拘泥于某一个技术的一点,技术是相通的.重要的是编程思想,思想是最重要的.当数据量大的时候,需要具有分的思想去细化粒度.当数据量太碎片的时候,需要具有合的思想来粗化粒度. ...

  7. [需求设计]从一个小需求感受Redis的独特魅力

    分享一个简单的小需求应该怎么设计实现以及有关Redis的使用 Redis在实际应用中使用的非常广泛,本篇文章就从一个简单的需求说起,为你讲述一个需求是如何从头到尾开始做的,又是如何一步步完善的.之前写 ...

  8. requests请求库练习--GitHub登录

    # coding = utf-8 """ 结合抓包工具,采用两种方法模拟登录github直接利用session登录和利用requests登录 ""&q ...

  9. SpringCloud Alibaba微服务实战一 - 基础环境准备

    Springcloud Aibaba现在这么火,我一直想写个基于Springcloud Alibaba一步一步构建微服务架构的系列博客,终于下定决心从今天开始本系列文章的第一篇 - 基础环境准备. 该 ...

  10. Layui下拉3级联动

    这里我就不给大家详细说明了直接附图: js代码: layui.use(['layer', 'form','xform','layer'], function () { var element = la ...