As we know that Django is one of the most powerful Python framework for Web Development. In django, sometimes we have to deal with huge amount of data in the database and render them simultaneously.

Kudos to django developers, who provides both high-level and low-level ways to manage paginated data that is splitting the data across several pages instead of showing all the contents of the object once. To implement infinite scrolling, we will be using django's  Paginator class  and a jQuery plug-in called  jScroll .

jScroll is a jQuery plugin for creating infinite scrolling in websites that has the ability to load content via AJAX within the current page when the user scroll to the bottom of the page.

 

How jScroll works?

jScroll loaded the new content automatically each time when we scroll to the end of the existing content by triggering to load by clicking a navigation link at the existing content and appending new data to the selected container.

 

Okay, these are all theories upto now. Let's start the project on infinite scrolling.

I assumed that you have already created your django project and ready to integrate infinite scrolling in your project.

Note: I have already created django project called infinite_scrolling with one app named books.

 

About the infinite_scrolling project

Here for demonstration purpose, we will be creating   Book model  that holds information like tilte, author, description and image and we will display book informations in the listview by allowing each page to display limited amount of informations.

 

Step 1: Creating Book model

Edit the  models.py  module of books app

from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=50)
    author = models.CharField(max_length=50)
    description = models.TextField(max_length=500)
    image = models.ImageField(blank=True, upload_to='book_images')

    def __str__(self):
        return self.title

 

Note: As we are using  ImageField   in Book model. We will need to install the Pillow library to handle images through pip.

pip install pillow

 

After installing pillow library, to enable django to server media files uploaded by users with the development server, add the following settings to the  settings.py  of your project as like:

 

settings.py

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),]

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

 

Now, we have to update the main  urls.py  of infinite_scrolling project as follows:

infinite_scrolling > urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('books.urls')),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)

By doing this, django development server serves the media files when  DEBUG = True .

 

At last, let's create new python module  urls.py  for the books app. This module performs background tasks by mapping urls path expressions to views functions.

books > urls.py

from django.urls import path
from .views import BookListView

urlpatterns = [path('', BookListView.as_view(), name='book-list')]

 

 BookListView  is the class based view in the  views.py  file inside books app that we are going to define in the next step.

 

Step 2: Creating BookListView view

from .models import Book
from django.views.generic import ListView


class BookListView(ListView):
    model = Book
    context_object_name = 'books'
    paginate_by = 5
    template_name = 'books/book-list.html'

 

What we have done above?

→ First we import the Book model from the  models.py  of books app.

→ Second to display list of objects, we import ListView from class  django.views.generic  which is the built-in feature offered by django.

→ Then we created class-based view  BookListView 

  • Inside the class we have specified  model = Book  which is same like  Book.objects.all() 
  • We specified  context_object_name = ' books'  for query results. Note: If you do not specify any context_object_name, the default variable will be 'object_list'
  • We assinged  paginate_by = 5  to display five objects per page
  • At last, we specified the  template_name = 'books/book-list.html'  to render our objects

 

Step 3: Creating template book-list.html

Inside the books directory, we would need to create a new folder called templates and inside it create another folder with name of the app i.e books and again inside books folder create html template book-list.html. It should be look like this:

|
|__ books
    |
    |__ templates
        |
        |__ books
            |
            |__ book-list.html

 

book-list.html

{% load static %}
<!doctype html>
<html lang="en">

<head>
    <!-- meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS CDN -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
          integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <title>Books – CodeFires</title>
</head>

<body>
<!-- container for showing book lists -->
<div class="container">
    <h1>Books</h1>
    {% if books %}
        <div class="book-list">
            {% for book in books %}
                <div class="card mb-3">
                    <img src="{{ book.image.url }}" class="card-img-top" alt="...">
                    <div class="card-body">
                        <h5 class="card-title">{{ book.title }}</h5>
                        <p class="card-text">{{ book.description }}</p>
                        <p class="card-text"><small class="text-muted">{{ book.author }}</small></p>
                    </div>
                </div>
            {% endfor %}
            {% if page_obj.has_next %}
                <p class="pagination">
                    <a class="next-page" href="?page={{ page_obj.next_page_number }}">More...</a>
                </p>
            {% endif %}
        </div>
    {% else %}
        <p>There are no any books uploaded yet!!!</p>
    {% endif %}
</div>

<!-- jQuery CDN hosted by Google -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- jScroll plug-in CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jscroll/2.4.1/jquery.jscroll.min.js"></script>

<script>
    jQuery(function ($) {
        var $list = $('.book-list');
        $list.jscroll({
            loadingHtml: '<div class="text-center">' +
                '<img src="{% static 'img/loading.gif' %}" alt="Loading" />' +
                '</div>',
            padding: 100,
            pagingSelector: '.pagination',
            nextSelector: 'a.next-page:last',
            contentSelector: '.card,.pagination'
        });
    });
</script>
</body>
</html>

 

Let's discuss what we have done in template by dividing into different sections:

Header section

<head>
    --------------------------

    <!-- Bootstrap CSS CDN -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
          integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">

    --------------------------
</head>

We have used CSS framework Bootstrap CDN(Content Delivery Network) for building attractive and responsive webpage. Simply copy the link from Bootstrap official website and paste them inside you <head>....</head> tags.

 

Body section

I assumed that there is no need of explanation in the container part for showing book lists, as it is pretty much clear. Well, the main part of this tutorial are following scripts because without them we cannnot create infinite scrolling in our project.

 

Scripts
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jscroll/2.4.1/jquery.jscroll.min.js"></script>

We have placed jQuery CDN hosted by Google and Cloudflare CDN URL to load the jScroll plug-in to the bottom of the closing <body> tag rather than downloading separately.

 

Loading jScroll method inside <script> tags
<script>
    jQuery(function ($) {
        var $list = $('.book-list');
        $list.jscroll({
            loadingHtml: '<div class="text-center">' +
                '<img src="{% static 'img/loading.gif' %}" alt="Loading" />' +
                '</div>',
            padding: 100,
            pagingSelector: '.pagination',
            nextSelector: 'a.next-page:last',
            contentSelector: '.card,.pagination'
        });
    });
</script>

 

  • loadingHTML⇒ HTML code to show loading spinner at the bottom of the list while loading a new page of items
  • padding⇒ Distance from the bottom of the scrollable page at which the new page should be loaded. Here in the example we give padding of 100
  • pagingSelector⇒ Simply select the class that have the responsibility of linking to another pages and hides the element in browsers when the jScroll plugin activated
  • nextSelector⇒ A selector for finding the next link of page with the href attribute
  • contentSelector⇒ A selector that specifies which HTML elements should be extracted from AJAX-loaded content and added to the container.

 

Finally, run the project using command  python manage.py runserver . You will noticed that whenever scrolling down, the later pages are loaded and attached at the bottom until all the objects are completely loaded. In this way, we successfully implemented infinite scrolling in our project.
 
You can check this project for reference on github: github.com/thecodefires/infinite-scrolling-django
 

Happy Learning :-)