(Comments)
Pagination is, dividing data into multiple pages each of fixed size. Modern web applications host huge amounts of data and returning all the data at once is not only not user-friendly but it can choke the network.
Django's paginator takes a list of objects and size of a page, then divides the list into individual pages and provide various methods to retrieve and manage pages and objects.
The Django official documentation provides the following code example which demonstrate how paginator works.
>>> from django.core.paginator import Paginator >>> objects = ['john', 'paul', 'george', 'ringo'] >>> p = Paginator(objects, 2) >>> p.count 4 >>> p.num_pages 2
Paginators take a list (or a queryset) and page number, then divide the list into pages.
>>> type(p.page_range) # `<type 'rangeiterator'>` in Python 2. <class 'range_iterator'> >>> p.page_range range(1, 3) >>> page1 = p.page(1) >>> page1 <Page 1 of 2> >>> page1.object_list ['john', 'paul'] >>> page2 = p.page(2) >>> page2.object_list ['george', 'ringo'] >>> page2.has_next() False >>> page2.has_previous() True
A page from paginator also provides methods to check if it is the last pages in the list, or if it the first page.
>>> page2.has_other_pages() True >>> page2.next_page_number() Traceback (most recent call last): ... EmptyPage: That page contains no results >>> page2.previous_page_number() 1 >>> page2.start_index() # The 1-based index of the first item on this page 3 >>> page2.end_index() # The 1-based index of the last item on this page 4 >>> p.page(0) Traceback (most recent call last): ... EmptyPage: That page number is less than 1 >>> p.page(3) Traceback (most recent call last): ... EmptyPage: That page contains no results
Let us assume we have a model called Movie
. Our view will look for a url parameter named page
which gives the page number of the page the user wants. Then our view is defined like this:
def view_movies(request): all_movies = Movies.objects.all() page_number = request.GET.get('page') paginator = Paginator(all_movies, 10) # 10 items per page movies = paginator.page(page_number) return render(request, 'list_movies.html', {'movies': movies})
all_movies
object is the queryset that includes all the movies in the database. The paginator takes the queryset and returns a single page object. We pass this page object to the context of the template. Our template will make use of the page as follows:
{% for movie in movies %} <h3>{{movie.title}}</h3> {#... use some html to display details ... #} {% endfor %} <div> {% if movies.has_previous %} <a href="?page={{movies.previous_page_number}}">Previous</a> {% else %} <span>Previous</span> {% endif %} <span> Page {{movies.number}} of {{movies.paginator.num_pages}}. </span> {% if movies.has_next %} <a href="?page={{movies.next_page_number}}">Next</a> {% else %} <span>Next</span> {% endif %} </div>
The paginator class gives us methods to check if there exists a next page, or a previous page. We are using them in the template to display the links to the next and previous pages. We are also using the number()
and num_pages()
to show the page numbers and the total number of pages.
While our view and template is good enough to show the list, we need to handle possible exceptions. We change our view method to the following:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render def view_movies(request): all_movies = Movies.objects.all() page_number = request.GET.get('page') paginator = Paginator(all_movies, 10) # 10 items per page try: movies = paginator.page(page_number) # This can raise an error except PageNotAnInteger: # If the page number is not an integer # show the first page movies = paginator.page(1) except EmptyPage: # If the page number is out of range # show the last page movies = paginator.page(paginator.num_pages) return render(request, 'list_movies.html', {'movies': movies})
We handled some of the possible errors while dealing with the pagination.
We develop web applications to our customers using python/django/angular.
Contact us at hello@cowhite.com
Comments