It is very simple when using a class-based view.
In views.py
:
from django.views.generic import ListView
class YourPaginatedListView(ListView):
...
paginate_by = 20
In your template, some version of this:
{% if is_paginated %}
<nav>
<ul>
<li>
<a href="{% if page_obj.has_previous %}?page=1{% endif %}">
First Page
</a>
</li>
<li>
<a href="{% if page_obj.has_previous %}?page={{ page_obj.previous_page_number }}{% endif %}">
Previous Page
</a>
</li>
<li>
<a>{{ page_obj.number }} / {{ page_obj.paginator.num_pages }}</a>
</li>
<li>
<a href="{% if page_obj.has_next %}?page={{ page_obj.next_page_number }}{% endif %}">
Next Page
</a>
</li>
<li>
<a href="{% if page_obj.has_next %}?page={{ page_obj.paginator.num_pages }}{% endif %}">
Last Page
</a>
</li>
</ul>
</nav>
{% endif %}
If you are not using a CBV, take a look at the docs for Using Paginator in a view.
Update:
Since you are processing the object list, try something like this in your view to only process the objects on the current page:
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from .models import YourModel
class YourPaginatedListView(ListView):
...
paginate_by = 20
def get_context_data(self, **kwargs):
context = super(YourPaginatedListView, self).get_context_data(**kwargs)
object_list = YourModel.objects.all()
paginator = Paginator(object_list, self.paginate_by)
page = self.request.GET.get('page')
try:
current_objects = paginator.page(page)
except PageNotAnInteger:
current_objects = paginator.page(1)
except EmptyPage:
current_objects = paginator.page(paginator.num_pages)
# Process the objects on the current page here
context['object_list'] = current_objects
return context