Django有内置的分页类,这个类位于django/core/paginator.py中,要使用这个类需要导入。
普通视图函数分页
假如我们要建一个博客网站,需要在让帖子在列表里显示,下面这个是没有分页功能的视图函数:
def index(request):
posts=Post.objects.all()
return render(request,'list.html',
{'posts':posts})
现在给它加上分页功能:
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
def post_list(request):
post_list = Post.published.all()
paginator = Paginator(post_list,3)
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,'list.html',{'post_list':post_list})
- 首先导入分页模块,然后获取全部的文章,保存在post_list
- 将想要分页的对象和数量传入Paginator,获得一个Paginator类的实例对象
- 获取用户请求的页码,传入page
- 用page()方法获取用户请求的文章列表,如果用户请求的页数不是整数就返回第一页,如果超出了总的页面数就到达最后一页
- 首先将要分类的对象实例化
- 从GET里面获得page参数来指明页数
- 调用Paginator的page()方法获得期望的页面对象
接下来就是在模板中使用了,代码如下:
{% if post_list.has_previous %}
<a href="?page={{ post_list.previous_page_number }}">Previous</a>
{% endif %}
Page {{ post_list.number }} of {{ post_list.paginator.num_pages }}
{% if post_list.has_next %}
<a href="?page={{ post_list.next_page_number }}">Next</a>
{% endif %}
Django会将问号后面的参数保存在django.GET里面,所以在前面的视图中用get方法获取page。has_previous和has_next是内置的接口,具体请参考Django官方文档。这样分页功能就已经完成了。
类视图的分页
类视图的分页比较简单,在列表视图ListView里面有一个paginate_by属性,可以用它来实现分页效果:
from django.views.generic import ListView
class PostListView(ListView):
model = Post
paginate_by = 3
template_name = 'list.html'
当我们使用了类视图后,Django会自动的生成3个上下文对象:
- paginator: 这是一个Paginator的实例,就是普通视图里面的paginator对象
- page_obj: 这是一个Page的实例
- is_paginated: 这是一个布尔值,表示是否已经分页
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Next</a>
{% endif %}