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 %}

๐Ÿง  Test Your Knowledge

What class is used for pagination in Django?