As we know that Django is one of the most powerful Python frameworks for Web Development. In Django, sometimes we have to deal with a 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 scrolls to the bottom of the page.
How jScroll work?
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 up to now. Let’s start the project on infinite scrolling.
I assumed that you have already created your Django project and are ready to integrate infinite scrolling into your project.
Note: I have already created a Django project called infinite_scrolling with one app named books.
About the infinite_scrolling project
Here for demonstration purposes, we will be creating a Book model that holds information like title, author, description, and image and we will display book information in the listview by allowing each page to display a limited amount of information.
Step 1: Creating a Book model
Edit the models.py
a module of the 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: We are using ImageField in the Book model. We will need to install the Pillow library to handle images through pip.
pip install pillow
After installing the 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 the 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, the Django development server serves the media files when DEBUG = True
.
At last, let’s create a 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 the 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 a 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 the same as 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 assigned 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 the name of the app i.e books, and again inside the books folder create HTML template book-list.html. It should 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 the template by dividing it 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 the CSS framework Bootstrap CDN(Content Delivery Network) for building an attractive and responsive webpage. Simply copy the link from Bootstrap’s official website and paste them inside your <head>….</head> tags.
Body section
I assumed that there is no need for explanation in the container part for showing book lists, as it is pretty much clear. Well, the main part of this tutorial is following scripts because without them we can not 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 has the responsibility of linking to another page and hides the element in browsers when the jScroll plugin activated
- nextSelector⇒ A selector for finding the next link of the 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.
python manage.py runserver
.Happy Learning 🙂