The pagination system is one of the most common features of a modern web application like blogs, search engines, a list of results, etc. It gives a better experience to the users.

How to Paginate with Django? - DEV Community

Seeing the popularity, Django came up with built-in pagination classes for paginating data of an application.

In this article, we will discuss the pagination process with class-based views and function-based views in Django.

We have a model named ‘Person’. We created some objects of that model. Till now we were showing all the objects of our model on the same page. Now we will use pagination on our page.

objects in our database

Adding Pagination In Class Based Views

We have used ListView to fetch all the Person objects. The ListView class supports pagination by default.

class AllPersonsView(ListView):
    model = Person
    template_name = 'all_persons.html'
    context_object_name = 'persons'
    paginate_by = 4

Here we have introduced a new attribute paginate_by which takes an integer specifying how many objects should be displayed per page. If this is given, the view will paginate objects with the value of  paginate_by attribute per page. The view will expect either a page query string parameter or a page variable specified in the URLconf.

Now our person objects are paginated by 4 persons a page.

Let’s create our ‘all_persons.html’

{% extends 'base.html' %}
{% load new_template_tags %}
{% block content %}
 
<!-- Looping Over 'persons' Queryeset -->

{% for person in persons %}
<a href="{% url 'person-detail-view' person.id %}">
    <h3>{{person.first_name  }} {{person.last_name  }}</h3>
</a>
<h4>Gender: {{ person.gender | custom_filter }}</h>
{% endfor %}

<!-- Pagination Part -->
{% if is_paginated %}
  <nav aria-label="Page navigation conatiner"></nav>
  <ul class="pagination justify-content-center">
    {% if page_obj.has_previous %}
   <a href="?page={{ page_obj.previous_page_number }}"class="page-link">&laquo;PREV </a>
    {% endif %}
    {% if page_obj.has_next %}
    <a href="?page={{ page_obj.next_page_number }}" class="page-link">NEXT&raquo;</a>
    {% endif %}
  </ul>
  </nav>
</div>
{% endif %}
{% endblock %}

If you are not familiar with Template Inheritance & Custom Template Tags, Filters. See these articles. Template Inheritance, Custom Template Tags, Filters.

Now let’s run the server and visit http://127.0.0.1:8000/all-persons you should see the page navigation buttons below the posts.

page 2

It was a simple work to add pagination in Class-Based Views. Now we will see how to add pagination in Function Based Views.

Adding Pagination Using Function-Based-Views

Django has a Paginator class. We will use that class to make equivalent function-based view for the above  AllPersonsView.

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

def all_persons(request):

    persons = Person.objects.all()
    paginator = Paginator(persons, 4)  # 4 persons in each page
    page = request.GET.get('page')

    try:
        persons_page = paginator.page(page)
        
    except PageNotAnInteger:
        # If person is not an integer deliver the first page
        persons_page = paginator.page(1)
       

    except EmptyPage:
        # If persons is out of range deliver last page of results
        persons_page = paginator.page(paginator.num_pages)

    return render(request, 'all_persons.html',{'page': page,'persons_page': persons_page,})

So, in this view, we instantiated the Paginator class with the number of objects to be displayed on each page. i.e 4. Then request.GET.get(‘page’) returns the current page number. The page() method is used to obtain the objects from the desired page number.

Below that we have two exception statements PageNotAnInteger and EmptyPage both are subclasses of InvalidPage. Then we have to render out the HTML file. Now let’s create our HTML file.

{% extends 'base.html' %}
{% load new_template_tags %}
{% block content %}
 
<!-- Looping Over 'persons' Queryeset -->
{% for person in persons_page %}
<a href="{% url 'person-detail-view' person.id %}">
    <h3>{{person.first_name  }} {{person.last_name  }}</h3>
</a>
<h4>Gender: {{ person.gender | custom_filter }}</h>
{% endfor %}

<!-- Pagination Part -->
{% if persons_page.has_other_pages %}
  <nav aria-label="Page navigation conatiner"></nav>
  <ul class="pagination justify-content-center">
    {% if persons_page.has_previous %}
    <li><a href="?page={{ persons_page.previous_page_number }}" class="page-link">&laquo; PREV </a></li>
    {% endif %}
    {% if persons_page.has_next %}
    <li><a href="?page={{ persons_page.next_page_number }}" class="page-link"> NEXT &raquo;</a></li>
   {% endif %}
  </ul>
  </nav>
</div>
{% endif %}

Let’s run the server and visit the URL below…

path('func-all-persons/', all_persons, name='all-persons'),

The output will be the same as before.

+ posts

Author | Python-Django Developer

+ posts

Full-stack Developer (Python | Django | React | React-Native | Angular | Vue)