Introduction
Pagination in Django is efficiently implemented using the Paginator class from django.core.paginator. It helps divide large querysets or lists into smaller, manageable chunks displayed page-by-page. This approach improves performance and enhances the user experience by preventing information overload.
To use pagination, you create a Paginator object with the queryset and the desired number of items per page. You can then access the appropriate page using the page() method. The resulting page_obj object, passed to the template context, offers attributes like has_previous, has_next, and number, enabling easy navigation.
1. Pagination with Function-Based Views (FBVs)
Here's an implementation of pagination in a function-based view:
  
  
  app/views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
from blog.models import Post
def post_list(request):
    list_of_posts = Post.objects.all()  # 1
    paginator = Paginator(list_of_posts, 5)  # 2
    page_number = request.GET.get("page", 1)  # 3
    try:
        posts = paginator.page(page_number)  # 4
    except PageNotAnInteger:
        posts = paginator.page(1)  # If page is not an integer, deliver first page.
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)  # If page is out of range, deliver last page.
    return render(request, "post/list.html", {"posts": posts})  # 5
Explanation:
- 
Retrieve Posts: All posts are retrieved using Post.objects.all().
- 
Create Paginator: A Paginatorobject is created to split the posts into pages, each containing 5 posts.
- 
Get Current Page: The page number is obtained from the URL's query parameters (e.g., ?page=2).
- 
Handle Exceptions:
- 
PageNotAnInteger: Defaults to page 1 if the provided page number is not an integer.
- 
EmptyPage: Defaults to the last page if the requested page exceeds the available pages.
 
- 
- 
Render Template: The list.htmltemplate is rendered with the paginated posts.
Pagination Template
The following template allows users to navigate between pages.
<!-- core/templates/pagination.html -->
<div class="pagination">
  <span class="step-links">
    {% if page_obj.has_previous %}
      <a href="?page=1">« First</a>
      <a href="?page={{ page_obj.previous_page_number }}">Previous</a>
    {% endif %}
    <span class="current">
      Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
    </span>
    {% 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 %}
  </span>
</div>
Explanation:
- Displays "Previous" and "Next" buttons depending on the availability of pages.
- Shows the current page number and the total number of pages.
Include the Pagination Template
To display the paginated posts and navigation links, include the pagination.html template in your main list template.
<!-- app/templates/post/list.html -->
{% block content %}
  <h1>My Blog</h1>
  {% for post in posts %}
    <h2>
      <a href="{{ post.get_absolute_url }}">
        {{ post.title }}
      </a>
    </h2>
    <p class="date">
      Published {{ post.publish }} by {{ post.author }}
    </p>
    {{ post.body|truncatewords:30|linebreaks }}
  {% endfor %}
  <!-- Include pagination -->
  {% include "pagination.html" with page_obj=posts %}
{% endblock %}
Note:
- The page_objvariable is passed explicitly via thewithclause to make it accessible in thepagination.htmltemplate.
2. Pagination with Class-Based Views (CBVs)
Django's ListView class provides built-in support for pagination, simplifying the implementation.
# app/views.py
from django.views.generic import ListView
from blog.models import Post
class PostListView(ListView):
    model = Post  # 1
    context_object_name = "posts"  # 2
    paginate_by = 5  # 3
    template_name = "post/list.html"  # 4
Explanation:
- 
Model: Specifies the Postmodel as the data source.
- 
Context Variable: Renames the default object_listtoposts.
- Pagination: Automatically paginates the results with 5 posts per page.
- 
Template: Uses the post/list.htmltemplate.
Pagination Template: Reuse the pagination.html template from the FBV implementation.
Error Handling for CBVs
To handle pagination exceptions explicitly in a CBV, override the paginate_queryset method:
# app/views.py
from django.core.paginator import EmptyPage, PageNotAnInteger
from django.views.generic import ListView
from blog.models import Post
class CustomPostListView(ListView):
    model = Post
    paginate_by = 5
    template_name = "post/list.html"
    def paginate_queryset(self, queryset, page_size):
        paginator = self.get_paginator(queryset, page_size)
        page_number = self.request.GET.get('page')
        try:
            page = paginator.page(page_number)
        except PageNotAnInteger:
            page = paginator.page(1)
        except EmptyPage:
            page = paginator.page(paginator.num_pages)
        return paginator, page, page.object_list, page.has_other_pages()
Explanation:
- 
PageNotAnInteger: If the provided page is invalid, display the first page.
- 
EmptyPage: If the page number is too large, display the last available page.
Include the Pagination Template
To display the paginated posts and navigation links, include the pagination.html template in your main list template.
<!-- app/templates/post/list.html -->
{% block content %}
  <h1>My Blog</h1>
  {% for post in posts %}
    <h2>
      <a href="{{ post.get_absolute_url }}">
        {{ post.title }}
      </a>
    </h2>
    <p class="date">
      Published {{ post.publish }} by {{ post.author }}
    </p>
    {{ post.body|truncatewords:30|linebreaks }}
  {% endfor %}
  <!-- Include pagination -->
  {% include "pagination.html" %}
{% endblock %}
Note:
The context variable page_obj is automatically included in the context of the Listview when pagniate_by is specified.
With these steps, you have a complete pagination system implemented in Django, supporting both function-based and class-based views with robust error handling and user-friendly navigation.
- Link for pagination in Django documentation
- Link of the HTML template in Django documentation
- Link to the Paginator() class in Django documentation
- Link to the template tag include()in Django documentation
 

 
    
Top comments (0)