When you start adding content to your blog, you will soon realize you need to split the list of posts across several pages. Django has a built-in pagination class that allows you to manage paginated data easily.
Edit the views.py
file of the blog
application to import the Django paginator classes and modify the post_list
view as follows:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger def post_list(request): object_list = Post.published.all() paginator = Paginator(object_list, 3) # 3 posts in each page page = request.GET.get('page') try: posts = paginator.page(page) except PageNotAnInteger: # If page is not an integer deliver the first page posts = paginator.page(1) except EmptyPage: # If page is out of range deliver last page of results posts = paginator.page(paginator.num_pages) return render(request, 'blog/post/list.html', {'page': page, 'posts': posts})
This is how pagination works:
Paginator
class with the number of objects we want to display in each page.page
GET parameter that indicates the current page number.page()
method of Paginator
.page
parameter is not an integer, we retrieve the first page of results. If this parameter is a number higher than the last page of results, we retrieve the last page.Now, we have to create a template to display the paginator, so that it can be included in any template that uses pagination. In the templates folder of the blog
application, create a new file and name it pagination.html
. Add the following HTML code to the file:
<div class="pagination"> <span class="step-links"> {% if page.has_previous %} <a href="?page={{ page.previous_page_number }}">Previous</a> {% endif %} <span class="current"> Page {{ page.number }} of {{ page.paginator.num_pages }}. </span> {% if page.has_next %} <a href="?page={{ page.next_page_number }}">Next</a> {% endif %} </span> </div>
The pagination template expects a Page
object in order to render previous and next links and display the current page and total pages of results. Let's go back to the blog/post/list.html
template and include the pagination.html
template at the bottom of the {% content %}
block, like this:
{% block content %}
...
{% include "pagination.html" with page=posts %}
{% endblock %}
Since the Page
object we are passing to the template is called posts
, we are including the pagination template into the post list template specifying the parameters to render it correctly. This is the method you can use to reuse your pagination template in paginated views of different models.
Now, open http://127.0.0.1:8000/blog/
in your browser. You should see the pagination at the bottom of the post list and you should be able to navigate through pages: