In this tutorial I will show you how to implement a very simple infinite scrolling with Django. Basically we will take advantage of Django’s pagination API and a jQuery plug-in. You will find examples using both function-based views and class-based views.
DependenciesWe don’t need anything other than Django installed in the back-end. For this example you will need jQuery and Waypoints.
jQuery 3.1.1 WaypointsAfter downloading the dependencies, include the following scripts in your template:
base.html<script src="{% static 'js/jquery-3.1.1.min.js' %}"></script> <script src="{% static 'js/jquery.waypoints.min.js' %}"></script> <script src="{% static 'js/infinite.min.js' %}"></script>
Basic ExampleThis example uses function-based view and I’m simply paginating a list of numbers, which I generate on the fly.
urls.py from django.conf.urls import url from mysite.blog import views urlpatterns = [ url(r'^$', views.home, name='home'), ] views.pyfrom django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render def home(request): numbers_list = range(1, 1000) page = request.GET.get('page', 1) paginator = Paginator(numbers_list, 20) try: numbers = paginator.page(page) except PageNotAnInteger: numbers = paginator.page(1) except EmptyPage: numbers = paginator.page(paginator.num_pages) return render(request, 'blog/home.html', {'numbers': numbers})
Here in this view, numbers_list represents a list of 1000 numbers, which I’m breaking down into blocks of 20 numbers per page. After paginating it, I return the numbers object to the template, which is a block of 20 numbers.
I won’t get into details about Django pagination because I have an article talking exclusively about it, so if you want to learn more, check this post: How to Paginate with Django .
Now here is where the magic happens:
blog/home.html {% extends 'base.html' %} {% block content %} <div class="infinite-container"> {% for number in numbers %} <div class="infinite-item">{{ number }}</div> {% endfor %} </div> {% if numbers.has_next %} <a class="infinite-more-link" href="?page={{ numbers.next_page_number }}">More</a> {% endif %} <script> var infinite = new Waypoint.Infinite({ element: $('.infinite-container')[0] }); </script> {% endblock %}The element identified by the class .infinite-container is the container where the plug-in will load more items. This action will occur every time the element .infinite-more-link appears in the screen. When that happens, it will trigger an asynchronous request (AJAX) loading the content from the URL specified in the href of the .infinite-more-link .
The page will keep loading new items until the .infinite-more-link is no longer shown. It will happen when there is no more items to be loaded. That is, the paginator reached the last page.
That’s why we have the conditional if numbers.has_next .
Adding Loading StateWe can improve the basic example by adding a loading state, while the page is grabbing more data.
blog/home.html {% extends 'base.html' %} {% block content %} <div class="infinite-container"> {% for number in numbers %} <div class="infinite-item">{{ number }}</div> {% endfor %} </div> {% if numbers.has_next %} <a class="infinite-more-link" href="?page={{ numbers.next_page_number }}">More</a> {% endif %} <div class="loading" style="display: none;"> Loading... </div> <script> var infinite = new Waypoint.Infinite({ element: $('.infinite-container')[0], onBeforePageLoad: function () { $('.loading').show(); }, onAfterPageLoad: function ($items) { $('.loading').hide(); } }); </script> {% endblock %}Our loading block will be shown while the AJAX is running in the background:
Image may be NSFW.
Clik here to view.

Class-Based View Example With Models
The idea remain the same. Actually, the example will become even cleaner. Consider the following model:
models.pyfrom django.db import models class Article(models.Model): title = models.CharField(max_length=30) body = models.TextField(max_length=2000) date = models.DateTimeField() author = models.CharField(max_length=30)
views.pyfrom django.views.generic.list import ListView from .models import Article class ArticlesView(ListView): model = Article paginate_by = 5 context_object_name = 'articles' template_name = 'blog/articles.html'
blog/articles.html {% extends 'base.html' %} {% block content %} <div class="infinite-container"> {% for article in articles %} <div class="infinite-item"> <h3>{{ article.title }}</h3> <p> <small>{{ article.author }} / {{ article.date }}</small> </p> <p>{{ article.body|truncatechars:100 }}</p> </div> {% endfor %} </div> <div class="loading" style="display: none;"> Loading... </div> {% if page_obj.has_next %} <a class="infinite-more-link" href="?page={{ articles.next_page_number }}">More</a> {% endif %} <script> var infinite = new Waypoint.Infinite({ element: $('.infinite-container')[0], onBeforePageLoad: function () { $('.loading').show(); }, onAfterPageLoad: function ($items) { $('.loading').hide(); } }); </script> {% endblock %}Just a small difference here, that since I’m using a ListView , the page object is available in the page_obj object in the template.
ConclusionsThat’s pretty much it! If you want to explore the example, the code is available on GitHub: github.com/sibtc/simple-infinite-scroll