In this Python tutorial, I will show you how to implement pagination in Django with Paginator. You will understand the concept of pagination and how it is helpful in showing a limited number of items on the webpage.
Then I will explain to you the classes with their properties and methods that you can use in Django to implement the pagination in your project. Additionally, you will implement all the concepts of pagination by building a project that lists the number of products on the page.
Also, you will learn how to make pagination controls so that you can move to different pages on the webpage to see the limited number of products on each page.
Pagination in Django with Paginator
Let’s start with an example, Suppose you are browsing an online bookstore, looking for a new book that you want to read. Now consider this situation where the store lists all the books on a single page something like a never-ending page which means you scroll pages continuously.
Again suppose a bookstore has thousands of books, and showing all these books on a single page may lead to the crash of the browser at the user end which is not a good user experience.
So what is the solution for that, and that is Pagination, In pagination large datasets are broken down into smaller chunks or datasets or you can call them pages. Pagination allows users to navigate through the dataset a page at a time, instead of showing all the datasets on a single page.
This means when pagination is implemented in the online book store, instead of showing a thousand books on a single page, the store lists some of the books per page like 50 books per page, the next 50 books on the second page and so on.
Now you understand the importance of pagination. Let’s learn how to implement pagination in the Django Project.
But before that, I will start with a simple example After that you will understand how to implement pagination in real world Django project.
To implement pagination in Django, there is a built-in class called Paginator in Django.
Pagination in Django with Paginator Project Configuration
First, let’s create a virtual environment named ‘page_env’ using the below command.
python -m venv page_env
Activate the environment ‘page_env’ using the below command.
page_env\Scripts\activate
Install the latest version of Django using the below command.
pip install django
Create a Django project named ‘page_project’ using the below command.
django-admin startproject page_project .
Now you open the project in your preferred IDE such as Visual Studio Code or you can continue with your command prompt or terminal.
Pagination in Django with Paginator Concepts
As you know Django provides a class Paginator to implement pagination, Here in this section, you will how to work with Paginator in Django to implement Pagination. The Paginator class exist in the django.core.paginator, so import the Paginator from this module.
from django.core.paginator import Paginator
Paginator works on datasets or large chunks, then it breaks down the dataset into smaller pages or chunks. Suppose in your database you have 50 products and when you fetch the product using Django, it returns Queryset which contains 50 products.
You can pass this Queryset to Paginator to divide it into smaller pages. For example, for each page containing 10 products, Paginator may break down the Queryset into 5 pages.
Let’s take an example, create a list of products containing the names of 10 products.
products = ["Iphone","Lenvo Laptop","Charger","Speedy Sneakers","Power Bank",
"BrightBook","MagicPencil","SkyHat","QuickCharger","GlowLamp"
]
You can consider this list of products as Queryset. Now Paginator take two parameters, the first one is the dataset or large chunks or Queryset and list of objects and the second is the number of data from the dataset which is how many data you want to show per page.
pages = Paginator(products, 5)
From the above, Paginator divides the products into 2 pages which means if the list of products has 10 products, then each page will have 5 products.
To know the total number of pages use the property num_pages as shown in the below code.
pages.num_pages
In the above output, you can see the Paginator divided the Queryset into 2 pages which means each page contains 5 products.
To know the range of page numbers, use the property page_range using the below code.
pages.page_range
So the range of Pages is from 1 to 3. To access each page, use the method page(page_number) by specifying the page number like this.
page1 = pages.page(1)
To access the data of the page or objects of each page, use the property object_list as shown in the below code.
To know the next page to the current page use the method has_next() on the current page as shown in the below code.
page1.has_next()
When the method has_next() is applied on the current page ‘page1’, it returns a boolean value that is True which means there is a next page.
To check the existence of the previous page, use the method has_previous() as shown in the below picture.
page1.has_previous()
The method has_previous() returns a boolean value as False which means there is no previous page to the current_page ‘page1’.
So to get the next and previous page numbers use the methods next_page_number() and previous_page_number() as shown in the below picture.
page2 = pages.page(2)
page2.previous_page_number()
page1.next_page_number()
If you apply the method next_page_number() on page2, it will throw an error as shown in the below picture.
page2.next_page_number()
The above error occurred because, after page2, there are no other pages, so it shows the error ‘EmptyPage’ as you know Paginator divided the given list of products or QuerySet into 2 pages.
Next, there are two more methods start_index() and end_index(), Let’s understand these methods with examples.
page2.start_index()
page2.end_index()
In the above code, the method start_index() shows the starting index of the first product of page2 and end_index() shows the last index of the last product of page2.
As you know page1 contains the product from 1 to 5 and page2 contains the product from 6 to 10.
Now you know how Paginator works in Django, let’s implement it with the Django project. So in this project, you will build a product page where a limited number of products will be shown per page with the help of Pagination.
Implementation of Pagination in Django with Paginator
Open the terminal and create a new Django app ‘page_app’ using the below command.
python manage.py startapp page_app
Or
django-admin startapp page_app
Create a model named ‘Product’ in the models.py file of your Django app ‘page_app’ and add the following line of code.
from django.db import models
class Product(models.Model):
product_name = models.CharField(max_length=50)
price = models.IntegerField(default=0)
description = models.CharField(max_length=200, default='')
image = models.URLField()
Now register the model in the admin.py file using the below code.
from django.contrib import admin
from .models import Product
# Register your models here.
admin.site.register(Product
Run the below command to migrate the model that comes with Django.
python manage.py migrate
Add the Django app ‘page_app’ in the setting.py file of your Django project ‘page_project’ using the below line of code.
INSTALLED_APPS = [
....,
'page_app',
]
Then migrate the model Product that you have created using the below command.
python manage.py makemigrations
python manage.py migrate
Create an admin user using the below command.
python manage.py createsuperuser
Run the Django server using the below command.
python manage.py runserver
Open the URL http://127.0.0.1:8000/admin enter the username and password that you have created, then click on the Login button.
After that click on the Product then click on the Add Product at the top right corner, then add the information about some products with product name, price, description and the product image URL as shown in the below picture.
Now create a view called product_list in the views.py file of your Django app ‘page_app’ and add the following lines of code.
from django.shortcuts import render
from .models import Product
def product_list(request):
products = Product.objects.all()
return render(request, 'product_list.html', {'products': products})
Also, create a new HTML file called product_list.html in the new folder called templates of your Django app ‘profile_app’ and add the following lines of code in the product_list.html file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product List</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100 p-10">
<h1 class="text-3xl mb-8 font-semibold">Product List</h1>
<span class="font-semibold mb-8">Number of Products on this Page: {{num_of_product}}</span>
<ul class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
{% for product in products %}
<li class="bg-white rounded-lg shadow p-4 flex flex-col items-center space-y-4">
<img src="{{ product.image }}" alt="{{ product.name }}" class="product-image w-32 h-32 object-cover rounded mb-4">
<div class="w-full text-center">
<strong class="text-lg block mb-2 truncate w-60">{{ product.name }}</strong>
<p class="text-gray-600 mb-2 truncate">{{ product.description }}</p>
<span class="text-green-500 font-semibold">Price: ${{ product.price }}</span>
</div>
</li>
{% endfor %}
</ul>
</body>
</html>
The above code in the template defined the layout and design of the product page. if you see the code like class=”bg-gray-100 p-10″, then this is the styling way of tailwind CSS framework which is used for styling elements of the webpage.
Set up the URLs for the Django project, so open the URLs.py file of your Django project ‘page_project’ and add the following line code.
from django.contrib import admin
from django.urls import path
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('page_app.urls'))
]
Also, set up the URLs for the Django app, so open the URLs.py file of your Django app ‘page_app’ and add the following line code.
from django.urls import path
from .views import product_list
urlpatterns = [
path('', product_list, name='product_list'),
]
Now run the Django server using the below code.
python manage.py runserver
After running the server go to the URL http://127.0.0.1:8000/, you see a page like this if you have added products to your database.
As you can see in the above picture, the single page contains 501 products, also look at the scroll button which is very small means you need to scroll down to see all the products. As I told you showing all the products on a single page is not a good user experience.
Sometimes loading or showing thousands of data items or products on a single page can lead to the crash of the browser. So to resolve this issue, implement the pagination.
For that open the view.py file of your Django app ‘profile_app’ and add the following lines of code.
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Product
def product_list(request):
product_list = Product.objects.all()
paginator = Paginator(product_list, 50)
page = request.GET.get('page')
try:
products = paginator.page(page)
except PageNotAnInteger:
products = paginator.page(1)
except EmptyPage:
products = paginator.page(paginator.num_pages)
return render(request, 'product_list.html', {'products': products})
In the above code at line 2, import the Paginator, EmptyPage and PageNotAnInteger. Then from lines 7 to 17, the following actions are done:
- In line 7, initializing the Paginator by passing the product_list Queryset and the integer value 5o to it, Which means dividing the product_list into pages, and each page should contain the 50 products.
- Then at line 9, access the value of the parameter ‘page’ that comes with the request using the request.GET.get(‘page’), which represents the page number that the user wants to view. That page number is saved into the variable page.
- At line 11 within the try block, get the specific page of products using the paginator.page(page) and store it into the variable products.
- After line 12, the code except PageNotAnInteger checks if the passed page number is not a valid integer, then the error PageNotAnInteger is raised. In this case, it gets the products from page number 1 using paginator.page(1) and stores it into variable products.
- After line 15, the code except EmptyPage checks if the passed page number is larger than the total number of pages, then the error EmptyPage is raised. In this case, it gets the products from the last page number using paginator.page(paginator.num_pages) and stores it into variable products.
Also, modify the template by adding the following line of code after the closing tag </u>.
<div class="mt-6">
<ul class="flex space-x-2 justify-center">
{% if products.has_previous %}
<li>
<a href="?page=1" class="px-3 py-2 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-500 hover:text-white">First</a>
</li>
<li>
<a href="?page={{ products.previous_page_number }}" class="px-3 py-2 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-500 hover:text-white">Previous</a>
</li>
{% endif %}
{% for i in products.paginator.page_range %}
{% if products.number == i %}
<li class="px-3 py-2 bg-blue-500 text-white border border-blue-500 rounded-lg">{{ i }}</li>
{% else %}
<li>
<a href="?page={{ i }}" class="px-3 py-2 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-500 hover:text-white">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if products.has_next %}
<li>
<a href="?page={{ products.next_page_number }}" class="px-3 py-2 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-500 hover:text-white">Next</a>
</li>
<li>
<a href="?page={{ products.paginator.num_pages }}" class="px-3 py-2 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-500 hover:text-white">Last</a>
</li>
{% endif %}
</ul>
</div>
In the above code from lines 26 to 56 define the pagination controls which allow users to navigate through different number pages.
The code at line 28 ‘if products.has_previous’ checks, if there is the existence of the previous page, if it is then it shows the two <li> elements such as First and Previous as a link so that when you click on these links it takes you to the first and previous pages.
Then at line 37, it loops through the range of page numbers for the ‘products’ queryset. The paginator.page_range attribute returns an iterable of page numbers, that allows you to loop through all the available pages.
- Within the loop, the code checks if the current page number ‘products.number’ is equal to the current iteration number (i). If that is true, it means this is the current page the user is viewing. Then it does the following things:
- The page number (i) is displayed within a list item <li> with a blue background, which visually shows the user that they are currently on that page.
- If false, the page number is displayed as a link <a> that, when clicked, will redirect the user to that specific page number.
Finally from lines 47 to 54, first, the code checks if there is a page after the current one using the ‘has_next’ attribute of the products queryset, if it returns true then the following things are done:
- A “Next” link, which redirects the user to the next page using products.next_page_number.
- A “Last” link, which redirects the user to the last page of the paginator using products.paginator.num_pages.
Save everything and run the Django server again using the below command.
python manage.py runserver
After running the server you see the products page as shown below.
As you can see in the above picture, the scroller is big in comparison to the scroller that you saw on the previous product list page, if the scroll is big it means there are less number of products.
As you implemented pagination and within the function, you specified the number of products per page should be 50 using this code Paginator(product_list, 50) if you remember.
So each page is going to contain 50 products, now scroll down to the bottom of the page as shown in the below picture.
As you scroll down, there are pagination controls that allow you to navigate through all the pages. So as you can, the current page is the 1 which is indicated by the blue color and this page contains 50 products.
Let’s move to the page second as shown in the below picture.
Now you are on the second page as you can see in the above picture, this is how you can switch to the other pages to view all the products.
The two links First and Last allow you to move quickly to the first and last page irrespective of the current page. Also, there are two links Previous and Next that allow you to move to the previous and next page from the current page.
Conclusion
In this Python tutorial, you learned how to implement pagination in Django with Paginator, and learned the important concept behind pagination and how to implement it in a real-world project. Then you build a small project where you implement all the concepts of pagination to show the limited number of products per page.
You may like to read:
- How to create an API in Python Django (using Generic Class API)
- Union operation on models Django
- How to Create App in Django
I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.