Django Pagination

  1. Create template tags

    1. create templatetags directory in app directory.

    2. create init.py and general_tags.py files inside.

    3. code for general_tags.py:

      from django.template.defaulttags import register
      
      from django import template
      register = template.Library()
      
      @register.inclusion_tag('pagination.html')
      def pagination(query, paginator_range):
          return {
              'query': query,
              'paginator_range': paginator_range,
          }
      
    4. create pagination.html file inside template directory:

      <hr>
      {% if query.has_other_pages %}
          <nav class="Page navigation d-flex justify-content-center">
              <ul class="pagination">
                  {% if query.has_previous %}
                      <li class="page-item"><a href="?page=1" class="page-link"><i class="fa fa-angle-double-left"></i></a></li>
                      <li class="page-item"><a href="?page={{ query.previous_page_number }}" class="page-link"><i class="fa fa-angle-left"></i></a></li>
                  {% else %}
                      <li class="page-item disabled"><a href="?page=1" class="page-link"><i class="fa fa-angle-double-left"></i></a></li>
                      <li class="page-item disabled"><a href="?page=1" class="page-link"><i class="fa fa-angle-left"></i></a></li>
                  {% endif %}
                  {% for i in paginator_range %}
                      {% if query.number == i %}
                          <li class="page-item active"><span class="page-link">{{ i }} <span class="sr-only">(current)</span></span></li>
                      {% else %}
                          <li class="page-item"><a href="?page={{ i }}" class="page-link">{{ i }}</a></li>
                      {% endif %}
                  {% endfor %}
                  {% if query.has_next %}
                      <li class="page-item"><a href="?page={{ query.next_page_number }}" class="page-link"><i class="fa fa-angle-right"></i></a></li>
                      <li class="page-item"><a href="?page={{ query.paginator.num_pages }}" class="page-link"><i class="fa fa-angle-double-right"></i></a></li>
                  {% else %}
                      <li class="page-item disabled"><a href="?page={{ query.paginator.num_pages }}" class="page-link"><i class="fa fa-angle-right"></i></a></li>
                      <li class="page-item disabled"><a href="?page={{ query.paginator.num_pages }}" class="page-link"><i class="fa fa-angle-double-right"></i></a></li>
                  {% endif %}
              </ul>
          </nav>
      {% endif %}
      
  2. create a function to prepare pagination:

    def prepare_pagination(query, page=1, items_per_page=20):
    	from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    
    	paginator = Paginator(query, 20)
    	adjacent_pages = 5
    	page = int(page)
    	start_page = max(page - adjacent_pages, 1)
    	if start_page <= 3: start_page = 1
    	end_page = page + adjacent_pages + 1
    	if end_page >= paginator.num_pages - 1: end_page = paginator.num_pages + 1
    	try:
    		query = paginator.page(page)
    	except PageNotAnInteger:
    		query = paginator.page(1)
    	except EmptyPage:
    		query = paginator.page(paginator.num_pages)
    	paginator_range = range(start_page, end_page)
    	return query, paginator_range
    
  3. Prepare pagination by calling above function in your view.py file for view function that requires it:

    def entities(request):
    	from datacore.models import NamedEntity
    	entities = NamedEntity.objects.all().order_by('text')
    	entities, paginator_range = prepare_pagination(query=entities, page=request.GET.get('page', 1))
    	context = {
    		'entities': entities,
    		'paginator_range': paginator_range,
    	}
    	return render(request, "entities.html", context)
    

    the variables paginator_range should be added to context, also here the pagination item is named entities which is passed to prepare_pagination function.

  4. in your template file:

    1. load your custom tag file at top of file:

      {% load general_tags %}
      
    2. call your pagination render function by calling it in your template:

      {% pagination entities paginator_range %}