#17 Pagination

I have published 17 lessons! Yey! But there is a problem, load time for landing page increases with each published page. So it is the right moment to introduce pagination.

Let's start with a very simple index view, which basically passes all available lessons to the django template.

    
def index(request):

    lessons = Lesson.objects.all()

    return render(
        request,
        'lessons/index.html',
        {
            'lessons': lessons
        }
    )
    

This code works for couple of items, like it worked for me up until recently. As the number of items (lessons) grows, the rendering of landing page increases. Paginations comes to rescue! The good news are that django web framework has built in pagination support. Above code needs to be changed as shown below:

    
from django.core.paginator import Paginator

def index(request):

    lessons = Lesson.objects.all()

    paginator = Paginator(lessons, per_page=3)
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)

    return render(
        request,
        'lessons/index.html',
        {
            'lessons': page_obj.object_list,
            'paginator': paginator,
            'page_number': int(page_number)
        }
    )
    

Paginator takes two arguments. A list of objects to paginate, which can be either a python's built in list or a Django's queryset instance and per_page argument which is number of items you want per page. Paginator instance provides a get_page(page_number) method which returns a Page class instance. In template we iterate over page's object list:

    
{% for i in paginator.page_range %}
        <li class="page-item">
            <a class="page-link" href="#">{{i}}</a>
        </li>
{% endfor %}
    

To enable users to navigate pages, we feed to each anchor "?page={{ i }}" argument. Then in the view we use it to extract, so to say, current page.

    
{% for i in paginator.page_range %}
    <li class="page-item {% if i == page_number %} active {% endif %}">
        <a class="page-link" href="?page={{ i }}">{{i}}</a>
    </li>
{% endfor %}
    

Pay attention to the elegant way used to highlight the active page. page_number argument is compared to the page iteration index, and if they match (which means that we are about to render current page), active css class is rendered. Also, notice that both i variable and page_number must be of same type (integer in the example above).