Pagination (Paginator, Page objects)
Pagination splits large QuerySets into pages, improving performance and user experience. Django provides the Paginator class for views and built-in pagination support for ListView. Paginator handles page numbers, boundary checks, and navigation.
15 min•By Priygop Team•Updated 2026
Pagination API
- Paginator(queryset, per_page) — Create paginator
- paginator.page(number) — Get specific page
- page.has_next() / page.has_previous() — Check neighbors
- page.next_page_number() / page.previous_page_number()
- paginator.num_pages — Total number of pages
- page.object_list — Items on current page
- InvalidPage exception for invalid page numbers
Pagination Example
Pagination Example
# blog/views.py — Function-based view
# from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
# def post_list(request):
# posts = Post.objects.filter(published=True)
# paginator = Paginator(posts, 10) # 10 posts per page
#
# page_number = request.GET.get('page', 1)
# try:
# page = paginator.page(page_number)
# except PageNotAnInteger:
# page = paginator.page(1)
# except EmptyPage:
# page = paginator.page(paginator.num_pages)
#
# return render(request, 'blog/list.html', {'page': page})
# Template — blog/list.html
# {% for post in page %}
# <h2>{{ post.title }}</h2>
# {% endfor %}
#
# <div class="pagination">
# {% if page.has_previous %}
# <a href="?page={{ page.previous_page_number }}">Previous</a>
# {% endif %}
# <span>Page {{ page.number }} of {{ page.paginator.num_pages }}</span>
# {% if page.has_next %}
# <a href="?page={{ page.next_page_number }}">Next</a>
# {% endif %}
# </div>
# ListView — built-in pagination
# class PostListView(ListView):
# model = Post
# paginate_by = 10
# # Template automatically gets 'page_obj'Tip
Tip
Always validate on the server side even if you have JavaScript validation. Client-side validation can be bypassed.
Diagram
Loading diagram…
QuerySets are LAZY — no DB hit until evaluated.
Common Mistake
Warning
Trusting client-side validation alone. Always validate on the server. Users can disable JavaScript or modify requests.
Practice Task
Note
(1) Add server-side validation for all fields. (2) Return errors to the template. (3) Test with invalid data.
Quick Quiz
Key Takeaways
- Pagination splits large QuerySets into pages, improving performance and user experience.
- Paginator(queryset, per_page) — Create paginator
- paginator.page(number) — Get specific page
- page.has_next() / page.has_previous() — Check neighbors