Pagination in Django
In this page:
Paginating a ListView
Setting paginate_by on a ListView is enough to split the queryset into pages of that size; Django handles slicing the data and figuring out the current page from a ?page= query parameter automatically.
Example: Paginating a ListView
paginate_by = 10 makes BookListView show 10 books per page, reading the page number from ?page= in the URL.
from django.views.generic import ListView
from .models import Book
class BookListView(ListView):
model = Book
paginate_by = 10
{# Django-only code -- models.py/views.py/urls.py/settings.py
snippets, or template markup using Django template tags/variables
-- can't run standalone via Judge0 or the browser preview, since
it needs a real Django project. Only this course's pure-Python
examples (example_lang == 'python', no Django imports) are
actually runnable, so those still get the button below. #}
Rendering Page Navigation
When paginate_by is set, the template gets page_obj (representing the current page) and is_paginated (True when there is more than one page), which together are enough to build Previous/Next links.
Example: Rendering Page Navigation
page_obj.has_previous/has_next and their matching page numbers drive the Previous/Next links shown to the user.
{% for book in page_obj %}
<p>{{ book.title }}</p>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<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>
{% endif %}
{% endif %}
{# Django-only code -- models.py/views.py/urls.py/settings.py
snippets, or template markup using Django template tags/variables
-- can't run standalone via Judge0 or the browser preview, since
it needs a real Django project. Only this course's pure-Python
examples (example_lang == 'python', no Django imports) are
actually runnable, so those still get the button below. #}
Manual Pagination with the Paginator Class
For a function-based view, Django's Paginator class provides the same splitting logic directly: give it a queryset and a page size, then ask it for a specific page.
Example: Manual Pagination with the Paginator Class
Paginator(Book.objects.all(), 10).get_page(...) produces the same page_obj a ListView would build automatically.
from django.core.paginator import Paginator
from django.shortcuts import render
from .models import Book
def book_list(request):
paginator = Paginator(Book.objects.all(), 10)
page_obj = paginator.get_page(request.GET.get('page'))
return render(request, 'books/book_list.html', {'page_obj': page_obj})
{# Django-only code -- models.py/views.py/urls.py/settings.py
snippets, or template markup using Django template tags/variables
-- can't run standalone via Judge0 or the browser preview, since
it needs a real Django project. Only this course's pure-Python
examples (example_lang == 'python', no Django imports) are
actually runnable, so those still get the button below. #}
- Forgetting that paginate_by only works automatically on ListView — a manual view needs the Paginator class used directly.
- Looping over object_list in the template while expecting pagination to be active without checking is_paginated or using page_obj.
- Not adding "Previous"/"Next" links in the template, leaving pagination working in the backend but unreachable for users.
- Pagination splits a long list of objects into smaller pages instead of showing everything at once.
- ListView paginates automatically once paginate_by is set to a page size.
- The template receives page_obj (the current page) and is_paginated (a boolean) to build navigation.
- Django's Paginator class can be used directly in function-based views for the same behavior.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: