首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Django Pagination 实现简单的分页功能

使用 Django Pagination 实现简单的分页功能

作者头像
追梦人物
发布2018-04-17 14:57:32
1.9K0
发布2018-04-17 14:57:32
举报

当网页上显示的数据过多时,通常需要进行分页显示。Django 内置的 Pagination 能够帮助我们实现简单的分页功能。

Paginator 类的常用方法

分页功能由 Django 内置的 Paginator 类提供。这个类位于 django/core/paginator.py,需要使用它时,只需在适当的地方导入这个类即可。

from django.core.paginator import Paginator

只需实例化一个 Paginator 对象,并在实例化时传入一个需要分页的对象列表,就可以得到分页后的对象数据。

# 对 item_list 进行分页,每页包含 2 个数据。
>>> item_list = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(item_list, 2)

取特定页的数据:

# 取第 2 页的数据
>>> page2 = p.page(2)
>>> page2.object_list
['george', 'ringo']

查询特定页的当前页码数:

>>> page2.number
2

查看分页后的总页数:

>>> p.num_pages
2

查看某一页是否还有上一页,以及查询该页上一页的页码:

# 查询第二页是否还有上一页
>>> page2.has_previous()
True

# 查询第二页上一页的页码
>>> page2.previous_page_number()
1

查看某一页是否还有下一页,以及查询该页下一页的页码:

# 查询第二页是否还有下一页
>>> page2.has_next()
False

# 查询第二页下一页的页码
>>> page2.next_page_number()
django.core.paginator.EmptyPage: That page contains no results

更多方法和属性请参阅 Django Pagination 的官方文档

用 Paginator 给文章列表分页

使用上面的一些方法,我们可以实现一个类似于 Django 官方博客一样的简单分页效果,效果如下。

假设我们在博客的首页展示全部文章,其对应的视图函数为:

def index(request):
    post_list = Post.objects.all()
    return render(request, 'blog/index.html', context={'post_list': post_list})

这里我们把全部文章取出来后存在 post_list 变量里,然后将它传递给了模板。现在来使用 Paginator 类对 post_list 进行分页。在视图函数里不再将全部的文章数据 post_list 传给模板了,而是把用户请求页的数据传给模板,这样用户看到的就是其请求页的文章数据。

视图函数修改如下:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def index(request):
    post_list = Post.objects.all() ①
    paginator = Paginator(post_list, 10) ②
    page = request.GET.get('page') ③

    try:
        post_list = paginator.page(page) ④
    except PageNotAnInteger:
        post_list = paginator.page(1) ⑤
    except EmptyPage:
        post_list = paginator.page(paginator.num_pages) ⑥

    return render(request, 'blog/index.html', context={'post_list': post_list})

① 获取全部的文章数据,保存在 post_list 中。

② 对 post_list 进行分页,每页 10 篇文章。为了测试分页你可以把数字改小点。

③ 获取用户请求页的页码。我们给页码设置的 URL 类似于 http://zmrenwu.com/?page=2。其中 ? 号后面的 page=2 表示用户请求的页码数。Django 会将问号后面的请求参数保存到 request.GET 属性里,这是一个类字典的属性。例如这里 page 作为键被保存,其值为 2。

④ 尝试获取用户请求页的文章列表。

⑤ 用户请求的 URL 中,page 的值可能不一定是整数,例如用户可能请求 http://zmrenwu.com/?page=xyz 这样的 URL。这时候将 page 作为参数传给 paginator.page 方法将抛出一个 PageNotAnInteger 异常。我们处理这个异常的方式是:将第一页的数据返回给用户。

⑥ 如果 page 的值是一个整数,但是值太大了。例如总共只有 4 页,但用户请求第 10 页的数据,这时候 paginator.page 方法会抛出 EmptyPage 异常。这里处理这个异常的方式是:返回最后一页的数据给用户。

在模板中设置分页导航

接下来便是在模板中设置分页导航,比如上一页、下一页的按钮,以及显示一些页面信息。我们这里设置和 Django 官方博客那样的分页导航样式(具体的样式见上图)。

在你想要显示分页信息的地方使用下面的代码。这里以 index.html 为例:

<div class="pagination">
  {% if post_list.has_previous %}
    <!-- 如果当前页还有上一页,显示一个上一页的按钮 -->
    <a href="?page={{ post_list.previous_page_number }}">上一页</a>
  {% endif %}
  <span class="current">
    <!-- 显示当前页面信息 -->
    第 {{ post_list.number }} 页 / 共 {{ post_list.paginator.num_pages }} 页
  </span>
  {% if post_list.has_next %}
    <!-- 如果当前页还有上下页,显示一个下一页的按钮 -->
    <a href="?page={{ post_list.next_page_number }}">下一页</a>
  {% endif %}
</div>

其中 {{ }} 模板变量中的内容,其含义已在文章开头部分的Paginator 类的常用方法中已有介绍。最终我们得到如下的分页效果:

当然这只是一个简单示例,分页导航处的视觉效果并不是很好看,你可以自行为其添加 CSS 样式使其看上去更加美观。

进一步拓展

使用 Django 内置的 Pagination 只能实现上面的简单分页效果,但通常更加高级的分页效果应该像下图这样:

当前页面高亮显示,且显示当前页面前后几页的页码,始终显示第一页和最后一页的页码,中间可能还有省略号的效果,表示还有未显示的页码。

仅仅使用 Django Pagination 内置的方法无法实现这样的效果,需要我们写一些额外的代码来拓展 Pagination 的功能。下一篇文章将详细说明该如何拓展 Pagination 以实现一个完善的分页效果。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Paginator 类的常用方法
  • 用 Paginator 给文章列表分页
  • 在模板中设置分页导航
  • 进一步拓展
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档