Django Pagination
Splitting large datasets into pages
๐ What is Pagination?
Pagination divides large lists of data into smaller pages, improving performance and user experience. Instead of loading thousands of items at once, Django shows manageable chunks with navigation controls.
# Simple pagination example
from django.core.paginator import Paginator
items = Article.objects.all()
paginator = Paginator(items, 10) # 10 items per page
page = paginator.get_page(1) # Get first page
Pagination Features
Page Size
Control items per page
paginator = Paginator(
items,
25 # 25 items per page
)
Page Numbers
Navigate between pages
page = paginator.get_page(2)
print(page.number) # 2
print(paginator.num_pages) # Total pages
Navigation
Previous and next page links
if page.has_previous():
prev = page.previous_page_number()
if page.has_next():
next = page.next_page_number()
Count Info
Display total items and pages
paginator.count # Total items
page.start_index() # First item number
page.end_index() # Last item number
๐น Basic Pagination in Views
Implement pagination in function-based views using Django's Paginator class. This splits your queryset into pages and handles page navigation automatically.
# views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
from .models import Article
def article_list(request):
# Get all articles
article_list = Article.objects.all().order_by('-created_at')
# Create paginator with 10 items per page
paginator = Paginator(article_list, 10)
# Get page number from URL parameter
page_number = request.GET.get('page')
# Get the page object
page_obj = paginator.get_page(page_number)
return render(request, 'articles.html', {'page_obj': page_obj})
URL Examples:
/articles/ โ Page 1
/articles/?page=2 โ Page 2
/articles/?page=3 โ Page 3
๐น Pagination Template
Display paginated items and navigation controls in your template. Django provides helpful methods to check for previous/next pages and display page numbers.
<!-- articles.html -->
<h2>Articles</h2>
<!-- Display articles -->
{% for article in page_obj %}
<div class="article">
<h3>{{ article.title }}</h3>
<p>{{ article.content|truncatewords:30 }}</p>
<small>Published: {{ article.created_at }}</small>
</div>
{% endfor %}
<!-- Pagination controls -->
<div class="pagination">
<span class="page-info">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
</span>
{% if page_obj.has_previous %}
<a href="?page=1">First</a>
<a href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
</div>
๐น Class-Based View Pagination
Use ListView with built-in pagination support for cleaner code. Just set paginate_by and Django handles everything automatically.
# views.py
from django.views.generic import ListView
from .models import Article
class ArticleListView(ListView):
model = Article
template_name = 'articles.html'
context_object_name = 'articles'
paginate_by = 10
ordering = ['-created_at']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['total_articles'] = Article.objects.count()
return context
# urls.py
from django.urls import path
from .views import ArticleListView
urlpatterns = [
path('articles/', ArticleListView.as_view(), name='article_list'),
]
๐น Advanced Pagination Template
Create a more sophisticated pagination interface with page number links and ellipsis for better navigation through many pages.
<!-- Showing items info -->
<p class="results-info">
Showing {{ page_obj.start_index }} to {{ page_obj.end_index }}
of {{ page_obj.paginator.count }} results
</p>
<!-- Advanced pagination controls -->
<div class="pagination">
{% if page_obj.has_previous %}
<a href="?page=1" class="page-link">ยซ First</a>
<a href="?page={{ page_obj.previous_page_number }}" class="page-link">โน Prev</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<span class="page-current">{{ num }}</span>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a href="?page={{ num }}" class="page-link">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}" class="page-link">Next โบ</a>
<a href="?page={{ page_obj.paginator.num_pages }}" class="page-link">Last ยป</a>
{% endif %}
</div>
Rendered Pagination:
Showing 11 to 20 of 156 results
ยซ First โน Prev | 1 [2] 3 4 5 | Next โบ Last ยป
๐น Pagination with Filters
Combine pagination with search and filter functionality while preserving query parameters across page navigation.
# views.py
def search_articles(request):
query = request.GET.get('q', '')
category = request.GET.get('category', '')
articles = Article.objects.all()
if query:
articles = articles.filter(title__icontains=query)
if category:
articles = articles.filter(category=category)
paginator = Paginator(articles, 10)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'page_obj': page_obj,
'query': query,
'category': category,
}
return render(request, 'search.html', context)
<!-- Preserve filters in pagination links -->
<a href="?q={{ query }}&category={{ category }}&page={{ page_obj.next_page_number }}">
Next
</a>
๐น Custom Paginator
Create a reusable pagination template tag for consistent pagination across your site.
# templatetags/pagination_tags.py
from django import template
register = template.Library()
@register.inclusion_tag('pagination.html')
def paginate(page_obj, request):
"""Render pagination controls"""
return {
'page_obj': page_obj,
'request': request,
}
<!-- Usage in templates -->
{% load pagination_tags %}
{% for article in page_obj %}
<!-- Display articles -->
{% endfor %}
{% paginate page_obj request %}