Pagination

Django provides high-level and low-level ways to help you manage paginated data– that is, data that’s split across several pages, with “Previous/Next” links.

The Paginator class

Under the hood, all methods of pagination use thePaginator class. It does all the heavy liftingof actually splitting a QuerySet into parts and handing them over to othercomponents.

Example

Give Paginator a list of objects, plus thenumber of items you’d like to have on each page, and it gives you methods foraccessing the items for each page:

  1. >>> from django.core.paginator import Paginator
  2. >>> objects = ['john', 'paul', 'george', 'ringo']
  3. >>> p = Paginator(objects, 2)
  4.  
  5. >>> p.count
  6. 4
  7. >>> p.num_pages
  8. 2
  9. >>> type(p.page_range)
  10. <class 'range_iterator'>
  11. >>> p.page_range
  12. range(1, 3)
  13.  
  14. >>> page1 = p.page(1)
  15. >>> page1
  16. <Page 1 of 2>
  17. >>> page1.object_list
  18. ['john', 'paul']
  19.  
  20. >>> page2 = p.page(2)
  21. >>> page2.object_list
  22. ['george', 'ringo']
  23. >>> page2.has_next()
  24. False
  25. >>> page2.has_previous()
  26. True
  27. >>> page2.has_other_pages()
  28. True
  29. >>> page2.next_page_number()
  30. Traceback (most recent call last):
  31. ...
  32. EmptyPage: That page contains no results
  33. >>> page2.previous_page_number()
  34. 1
  35. >>> page2.start_index() # The 1-based index of the first item on this page
  36. 3
  37. >>> page2.end_index() # The 1-based index of the last item on this page
  38. 4
  39.  
  40. >>> p.page(0)
  41. Traceback (most recent call last):
  42. ...
  43. EmptyPage: That page number is less than 1
  44. >>> p.page(3)
  45. Traceback (most recent call last):
  46. ...
  47. EmptyPage: That page contains no results

Note

Note that you can give Paginator a list/tuple, a Django QuerySet,or any other object with a count() or len() method. Whendetermining the number of objects contained in the passed object,Paginator will first try calling count(), then fallback to usinglen() if the passed object has no count() method. This allowsobjects such as Django’s QuerySet to use a more efficient count()method when available.

Paginating a ListView

django.views.generic.list.ListView provides a builtin way to paginatethe displayed list. You can do this by addingpaginate_by attribute toyour view class, for example:

  1. from django.views.generic import ListView
  2.  
  3. from myapp.models import Contacts
  4.  
  5. class ContactsList(ListView):
  6. paginate_by = 2
  7. model = Contacts

The only thing your users will be missing is a way to navigate to the next orprevious page. To achieve this, add links to the next and previous page, likeshown in the below example list.html.

Using Paginator in a view

Here’s a slightly more complex example usingPaginator in a view to paginate a queryset. Wegive both the view and the accompanying template to show how you can displaythe results. This example assumes you have a Contacts model that hasalready been imported.

The view function looks like this:

  1. from django.core.paginator import Paginator
  2. from django.shortcuts import render
  3.  
  4. def listing(request):
  5. contact_list = Contacts.objects.all()
  6. paginator = Paginator(contact_list, 25) # Show 25 contacts per page
  7.  
  8. page = request.GET.get('page')
  9. contacts = paginator.get_page(page)
  10. return render(request, 'list.html', {'contacts': contacts})

In the template list.html, you’ll want to include navigation betweenpages along with any interesting information from the objects themselves:

  1. {% for contact in contacts %}
  2. {# Each "contact" is a Contact model object. #}
  3. {{ contact.full_name|upper }}<br>
  4. ...
  5. {% endfor %}
  6.  
  7. <div class="pagination">
  8. <span class="step-links">
  9. {% if contacts.has_previous %}
  10. <a href="?page=1">&laquo; first</a>
  11. <a href="?page={{ contacts.previous_page_number }}">previous</a>
  12. {% endif %}
  13.  
  14. <span class="current">
  15. Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
  16. </span>
  17.  
  18. {% if contacts.has_next %}
  19. <a href="?page={{ contacts.next_page_number }}">next</a>
  20. <a href="?page={{ contacts.paginator.num_pages }}">last &raquo;</a>
  21. {% endif %}
  22. </span>
  23. </div>