Django Pagination

In this post, you’ll be learning about Django Pagination.

Table of Contents

Setup Project

Create App and Migrate Models

Now create a new app and name it filter_and_pagination then make app discoverable by adding it to INSTALLED_APPS in
For our post, we’ll be taking an example of Books and Authors and display them in a table.

I have created two models Book and Author then migrate them to the database.

from django.db import models

# Create your models here.
class Book(models.Model):
        ('PUBLISHED', 'Published'),
        ('ON_HOLD', 'On Hold'), 
    id = models.AutoField(primary_key=True)
    book_name = models.CharField(max_length=255)
    author = models.ForeignKey('Author',on_delete=models.CASCADE,related_name='author')
    status = models.CharField(max_length=255, choices = BOOK_STATUS)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:

    def __str__(self):
        return self.book_name
    def get_status_verbose_name(self):
        for row in range(0,2):
            if self.BOOK_STATUS[row][0] == self.status:
                status_verbose = self.BOOK_STATUS[row][1]
        return status_verbose

class Author(models.Model):
    id = models.AutoField(primary_key=True)
    author_name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "authors"
        verbose_name = "Author"
        verbose_name_plural = "Authors"

    def __str__(self):
        return self.author_name

Migrate models using Django Migration commands we can see that table books and authors are created in database.

Making views and pagination

In we have list_data function and we are retrieving all books and sending to template for displaying.
To Paginate books queryset you have to import Paginator from django.core.paginator package.

The Paginator is a class it takes queryset list and per_page an integer as arguments then it is assigned to paginator object. The method paginator.get_page(page) takes page as an argument from a request query string request.GET.

As Django querysets are lazy they are not evaluated when we call Book.objects.all(). So there won’t be any performance lag for calling .all().

from django.shortcuts import render
from filter_and_pagination.models import Book, Author
from django.core.paginator import Paginator

# Create your views here.
def list_data(request):
    books = Book.objects.all()
    paginator = Paginator(books,3)
    page = request.GET.get('page')
    books = paginator.get_page(page)
        "books" : books
    return render(request,path,ctx)

In apps(filter_and_pagination)/ the url listing maps to list_data function in file.

app_name = 'filter_and_pagination'

urlpatterns = [
    path('listing', views.list_data, name='listing'),

Make template in path=”filter_and_pagination/templates/filter_and_pagination/filter_listing.html”

    <!DOCTYPE html>
    <html lang="en">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Book Listing</title>
        <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="">
            <div style="border: 1px dashed #333;" >
                <h5 style="text-align: center;" >Book Filtering</h5>
                <div class="" >
                    <ul class="pagination">
                        {% if books.has_previous %}
                            <li><a href="{% url 'filter_and_pagination:listing' %}?page={{books.previous_page_number}}"><span class="glyphicon glyphicon-chevron-left"></span></a></li>
                        {% endif %}
                        {% for num in books.paginator.page_range %}
                            {% if books.number == num %}
                                <li class="active"><a href="{% url 'filter_and_pagination:listing' %}?page={{num}}">{{num}}</a></li>
                            {% elif num > books.number|add:'-3' and num < books.number|add:'3' %}
                                <li><a href="{% url 'filter_and_pagination:listing' %}?{{filter_url}}&page={{num}}">{{num}}</a></li>
                            {% endif %}
                        {% endfor %}
                        {% if books.has_next %}
                            <li><a href="{% url 'filter_and_pagination:listing' %}?page={{books.next_page_number}}"><span class="glyphicon glyphicon-chevron-right"></span></a></li>
                        {% endif %}
            <div style="" >                
                <table border="1" style="border-collapse: collapse">
                            <th>Sl no</th>
                            <th>Book Name</th>
                            <th>Book Status</th>
                            <th>Total Books Count</th>
                        {% for book in books %}
                            <td>({{}}) <strong>{{}}</strong></td>
                        {% endfor %}


The books an object also has paginator properties.

  • has_previous: This property returns a boolean value. It returns True if the previous page exists.
  • number: returns the currently active page number.
  • paginator.count: returns total number of Objects.
  • paginator.num_pages: returns total number of pages.
  • paginator.page_range: This property returns a range of total pages. We can display page numbers by looping through this property.
  • has_previous: This property returns a boolean value. It returns True if the previous page exists.
  • has_next: returns True if next page exists.


Django Pagination Output


So we have come to the conclusion part of our Django Pagination post. If you like this then please share and for queries comment below. We’ll reach to you soon.

Recent Posts

Review Date
Reviewed Item
Django Pagination
Author Rating
Software Name
Django Pagination
Software Name
Windows Os, Mac Os, Ubuntu Os
Software Category
Web Development