Pagination in Django

As the situation stands, On every page of our blog, we are displaying all the posts at once. We don’t have many posts at this point, but if we had hundreds or thousands of posts then loading them all at once, could take a while. Implementing pagination not only makes the site load faster, but it is also great in terms of usability.

Django provides a class named Paginator which allows us to create paginated records. To use it, import it from django.core.paginator module.

To use pagination we, have to create a Paginator object first. Paginator constructor has the following syntax:

The object_list can be a tuple, list, Queryset, etc. The records_per_page is a number of records you want to show on each page.

Here is the code to create a Paginator object to show 5 post per page:

The Paginator object has the following attributes and methods, which are frequently used while creating paginated records.

Attribute/Method What it does?
count The count attribute returns the total number of records, across all the pages.
num_pages The num_pages attribute returns total number of pages.
page(number) The page() method accepts a page number and returns a Page instance for that page. We use Page instance to access records in a page. If the argument is not a number, then it throws PageNotAnInteger exception. However, If the page specified doesn't exist it throws an EmptyPage exception.

The Page object also provides some useful attributes and methods.

Attribute/Method What it does ?
object_list It returns an iterable object, which contains the records for the page number which we had passed to the Page() method.
number 1 based numeric count of the current page.
has_next() returns True if there is next page. Otherwise False.
has_previous() returns True if there is previous page. Otherwise False.
next_page_number() returns next page number. If next page doesn't exists it throws a django.core.paginator.InvalidPage exception
previous_page_number() returns previous page number. If previous page doesn't exists it throws a django.core.paginator.InvalidPage exception
paginator This attribute returns the Paginated object attached to the Page object.

Open Django shell and let’s try some of the things we have learned so far:

Get the records for the first page:

We can also access the Paginator object which created page1 object in the first place.

In fact, the object pointed to by page1.paginator and p are same. We can verify this fact by executing the following code.

Once we have access to Paginator object we can access it’s attributes and methods too.

Get the records for the second page:

I hope you get the idea here.

Once we have access to the Page object, we can use it in our template to loop over each item in the page. Consider the following code:

So all we need to do to use pagination is to pass Page object as context variable to the template. That’s it. We don’t need to modify our for tag to use Page object in anyway.

In the following few sections, we are implementing pagination in the home page, category page, and tag page.

Implementing pagination in home page

Our goal in this section is to build implement pagination which allows the user to access posts as follows:

  • Visit http://127.0.0.1:8000/ or http://127.0.0.1:8000/?page=1 to view posts on the first page
  • Visit http://127.0.0.1:8000/?page=2 to view posts on the second page
  • Visit http://127.0.0.1:8000/?page=3 to view posts on the third page and so on.

The ?page=3 part of the URL is called query string.

Open views.py and modify post_list() as follows:

TGDB/django_project/blog/views.py

The code for creating paginated records (from line 9 to 23) will be same, all across the views. As a result, instead of copying and pasting the same code multiple times, we can assign the task to a function. Create a new file named helpers.py in Django project configuration directory i.e TGDB/django_project/django_project (same place where settings.py is located) and put the pagination code in a function named pg_records(), which is defined as follows.

TGDB/django_project/django_project/helpers.py

To use helper function inside our views add the following code to the end of the import list in views.py.

TGDB/django_project/blog/views.py

Replace the code for pagination in post_list() view with the following code.

At this stage, post_list() view should like this:

TGDB/django_project/blog/views.py

To add pagination links to our template, open post_list.html and add the following code just below the closing <div class="content"> tag.

TGDB/django_project/blog/templates/blog/post_list.html

Save the file and visit http://127.0.0.1:8000/ to see the pagination in action.

Implementing pagination in other pages

To add pagination to category page and tag page first modify
post_by_category() and post_by_tag() view function in views.py file as follows:

TGDB/django_project/blog/views.py

Finally, add the following code to show pagination links to post_by_category.html and post_by_tag.html template just after the closing <div class="content"> tag in the content block.

Now all the pages in our blog have pagination.

Note: To checkout this version of the repository type git checkout 26a.

Leave a Comment