A single page application (SPA) is a web application, which runs in a browser, and does not require a page refresh to load new content. Django is a great framework for handling the backend of single-page applications.

This tutorial will walk you through the process of implementing a very simple single-page application using Django. We will take advantage of Django's views and JavaScript's fetch API.
We'll use Django as our backend, HTML and CSS  for the front-end, and JavaScript's fetch API for asynchronous communication between the backend and frontend. You can find the code for this tutorial here.

 

Setting Up the Project

You should have Django installed before starting a Django project. To Install Django run the command below in your terminal or workspace.

pip install django

 

To Start a Django Project :

django-admin startproject mysite

This will generate a project structure with several directories and python scripts which looks like:

├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── manage.py

To know more about the files created, read: Writing your first Django app.

 

After creating a Django project, we need to create a Django app for our single-page app. Every Django project must contain at least one app.

Navigate into the outer directory where manage.py script exists :

cd mysite

Then run this command:

python manage.py startapp singlepage

These will create an app named singlepage in our project.

Our project directory will look like this:

├── db.sqlite3
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── manage.py
└── singlepage
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations/
    ├── models.py
    ├── tests.py
    └── views.py

 

Adding singlepage app to Django settings.

After creating our first django app in the project, we need to inform django that a new application called singlepage has been created.

Open your settings.py file and scroll down to the installed apps

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

 

Now add the new app, singlepage to the installed apps

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'singlepage',                          # down here
]

 

 

Creating Views

We are going to be using function-based views. A Django view is a function that receives a request and returns a response.

Open your singlepage/views.py and write the code below:

views.py

from django.shortcuts import render
from django.http import HttpResponse, Http404


# Create your views here.
def index(request):
    return render(request, "singlepage/index.html")


texts = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tortor mauris, maximus semper volutpat vitae, varius placerat dui. Nunc consequat dictum est, at vestibulum est hendrerit at. Mauris suscipit neque ultrices nisl interdum accumsan. Sed euismod, ligula eget tristique semper, lecleo mi nec orci. Curabitur hendrerit, est in ",
        "Praesent euismod auctor quam, id congue tellus malesuada vitae. Ut sed lacinia quam. Sed vitae mattis metus, vel gravida ante. Praesent tincidunt nulla non sapien tincidunt, vitae semper diam faucibus. Nulla venenatis tincidunt efficitur. Integer justo nunc, egestas eget dignissim dignissim,  facilisis, dictum nunc ut, tincidunt diam.",
        "Morbi imperdiet nunc ac quam hendrerit faucibus. Morbi viverra justo est, ut bibendum lacus vehicula at. Fusce eget risus arcu. Quisque dictum porttitor nisl, eget condimentum leo mollis sed. Proin justo nisl, lacinia id erat in, suscipit ultrices nisi. Suspendisse placerat nulla at volutpat ultricies"]

def section(request, num):
    if 1 <= num <= 3:
        return HttpResponse(texts[num-1])
    else:
        raise Http404("No such section")

 

The texts variable is a list with 3 dummy texts. They may represent data from the database or a paginated list of blog articles.

The index and section functions are Django views. The index view just renders an HTML file called index.html, we will create that later.

The section view is the view we are going to send a request to in order to get the data from the texts list.

 

Creating the URLs.

After creating our views, we must create URLs that map to each of the views we created. It is through these URLs that we can access our views.

Create a urls.py file in your singlepage application directory and add the following code.

singlepage/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path("", views.index, name='index'),
    path("sections/<int:num>", views.section, name='section'),
]

The sections/<int:num> means accessing that URL requires an argument of type integer. Example : section/2.

If you don't know much about URLs, you can refer to the Django docs URL dispatcher.

 

Now we need to include these singlepage URLs to the actual project. By opening the mysite/urls.py file, you will see:

mysite/urls.py

from django.contrib import admin

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

 

Modify it to include the URLs from singlepage app:

from django.contrib import admin
from django.urls import path, include                   # new

urlpatterns = [
    path('admin/', admin.site.urls),
    path("", include("singlepage.urls")),               # new
]

Requests will now be directed to the singlepage app.

 

Creating Templates

Django allows us to handle HTML code separately from our views and other python code. We are going to keep HTML files in a template directory.

First, open the singlepage directory and create a folder or directory called templates. Secondly, in the templates directory, you create another directory called singlepage.

Finally, in the singlepage directory you just created, create an HTML file called index.html .

├── db.sqlite3
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── manage.py
└── singlepage
├── __init__.py
├── admin.py
├── apps.py
├── migrations 
├── templates                     # new directory
    ├── singlepage                # new directory
        ├── index.html            # new HTML file
├── models.py
├── tests.py
└── views.py

 

Now open your index.html and write the following code.

singlepage/templates/singlepage/index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Single Page</title>
        <script>

            //  This function communicates with django (backend)
            
            function showSection(section) {   
                fetch(`/sections/${section}`)
                .then(response => response.text())
                .then(text => {
                    console.log(text);
                    document.querySelector('#content').innerHTML = text;
                });

            }


            document.addEventListener("DOMContentLoaded", function() {
                document.querySelectorAll('button').forEach(button => {
                    button.onclick = function() {
                        showSection(this.dataset.section)
                    }
                })
            });


        </script>
    </head>
    <body>
        <h1>Hello</h1>
        <button data-section="1">Section 1</button>
        <button data-section="2">Section 2</button>
        <button data-section="3">Section 3</button>

        <!-- Contents loaded from server is inserted here by javascript -->
        <div id="content">

        </div>
    
    </body>
</html>

 

Now open your terminal and run :

python manage.py runserver

 

Open the link http://127.0.0.1:8000/ in your browser and if everything worked out  good you should get something like this:

 

When you click on any of the buttons, it loads different text from the backend(Django) into the page without reloading the page. It loads the content very fast because it is running on a local server. If it were on a remote server, it will take some time before the contents appear.

Loading content from the backend without reloading the page makes our app a single-page.

This is just a simple implementation. The texts being loaded from the backend could be a list of blog posts or some other data from a database, it could be anything.

You can find the code for this project on GitHub here.