In this article, we are going to add offline support to Django website using service workers and convert it to an awesome progressive web app.

What is a Progressive web app?

A Progressive Web App (PWA) is nothing but your existing web application with responsiveness and ability to provide some content of your web application when user is offline. We will use service workers and Cache API to add offline support in a web application.

Prerequisites:

Python (3.x)

Django (1.11 or higher)

HTML, CSS, JavaScript.

We all know that Django uses app approach. Every module in Django is called as an app. In order to enable progressive web app behavior in Django, we have to add a Django app called pwa to include a manifest.json and Service Worker instance to our website.

How we are going to proceed?

Create new Django project for demo purpose. (demo of feeds ) Add functionality to display news feed. Add service worker. Enable offline support using service worker.

Step 1: Create new Django project for demo purpose. (demo of feeds )

We will create new Django project called djangopwa. This project simply retrieves the news feed from server and displays on user’s page. we haven’t added the functionality of register, login, posting news and managing news added by the user. We will add it in future as we proceed further.

To create new project open command line go to your regular directory where you usually store all your projects and type following command.

django-admin startproject djangopwa

Now go to root directory djangopwa and type following command to create a new app called posts which will retrieve feeds from server using MySQL database and display it on browser.

django-admin startapp posts

Note: For this article, sometimes we will refer news feed as posts. Both are one and the same thing here.

After adding posts app, time to design our home page. Create a new folder called templates inside posts app. Create another folder posts inside templates folder. So now you have a directory like this:

djangopwa/posts/templates/posts

Inside this directory, we will be keeping all html files which will be served to the user. We are going to create index.html to display feeds and base.html. to define website layout.

If you are still confused about directory structure, take a look at the following picture:

directory structure for html files

Time to write some HTML stuff inside this two files! Let’s start with the layout of our website i.e. base.html file.

base.html :

Every other html file extends base.html file using template language. base.html contains navigation bar and footer with bootstrap and CSS links. We will register our service worker in base.html in next step.

index.html:

As we discussed earlier, index.html extends base.html and displays news feed inside <div class=”feeds”> using for loop. here results is template variable which holds a list of feeds sent by django view.py

Now that we have our html side ready, time to write some server side code inside views.py of posts app.

Step 2: Add functionality to display news feed.

views.py:

index() function is responsible to serve homepage of the website when user is online. results retrieves all the feeds and is sent to client side using context dict. base_layout() function is used to render base.html. which will be cached by service worker later on for offline support (we will see more about this later).

models.py:

This will be our simple database in MySQL. Make sure your table structure is same as this class feed and name the table as posts_feed .

I will leave a GitHub link of the same project at the end of this article. You can refer urls.py , settings.py and many other files from it.

Step 3: Add service worker.

Time to add offline support to our website! We need to install an app called pwa in our website to enable service worker functionality. Open command prompt and type following command:

pip install django-progressive-web-app

Once you are done with the installation, Add pwa app in our INSTALLED_APPS list in settings.py .

INSTALLED_APPS = [

'django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.messages',

'django.contrib.staticfiles',

'posts',

'pwa',

]

After adding pwa app, we need to define a url for the same. Add following line in urls.py file located in root directory of djangopwa .

path(‘’, include(‘pwa.urls’)),

This is how your urls.py should look like:

urls.py

pwa app added successfully in our website! Now the big question in front of us is where to place service worker JavaScript file and how to add it to our html files?

Create a folder named static inside posts , create another folder named js inside static . Now we will place all JavaScript files here including service workers and IndexedDB operations files. Now your directory structure for JavaScript files is djangopwa/posts/static/js/ To get a clear idea, take a look at the following picture.

directory structure for js files

Create a blank JavaScript file and name it as serviceworker.js . This is our service worker for djangopwa . Now we will need to tell our djangopwa application that our service worker resides in /static/js directory. To do that, we need to add below line in settings.py file below BASE_DIR variable.

PWA_SERVICE_WORKER_PATH = os.path.join(BASE_DIR, 'posts/static/js', 'serviceworker.js')

Refer the following picture to get clear view of settings.py file

Defining service worker path in settings.py file

In order to register this service worker, we will need to insert meta tags in our base.html file. Since every other html file extends base.html , once we register our service worker in base.html file it will be available on every page of the website. Open base.html file and insert following meta tags:

{% load pwa %}



<head>

...

{% progressive_web_app_meta %}

...

</head>

This is how your base.html file should look like:

<!DOCTYPE html>

<html>

{% load pwa %}

{% load static %}

<head>

{% progressive_web_app_meta %}

<title>Feeds</title>

<!-- rest is same as previous base.html file -->

Meta tags will register service worker for you defining the scope of service worker as / So service worker can have access to every page in your website. If you click on view source in right click options inside chrome browser you will see code of JavaScript in place of those meta tags. It will look something like this:

registration of service worker.

Now our service worker is registered successfully! Run your server and open application tab in developers tools from chrome. You will see your service worker registered and log in the console about the same.

Step 4: Enable offline support using service worker.

To enable offline support, we need to cache layout of the website defined by base.html and store feeds in IndexedDB so that it will be available to the user in offline mode. In this part, we will cache layout of the website using service worker.

serviceworker.js

Above code will cache /base_layout which is nothing but view function called base_layout() in our views.py file. base_layout() renders base.html file to he user. So basically, our service worker is caching base.html file at the time of install event. When the user requests for homepage i.e. when the user hits homepage of website / service worker gets match that requested url is / and responds to that request by serving cached base.html file to the user. Even if the user is offline, he will be served by cached response from service worker.

Open application tab in developers tools. Open cache storage. You will see cache named djangopwa-v1 . If you click on that you will see base_layout is cached and size of it. Refer the following picture:

cached layout of website

Now open service workers from application tab and tick the offline mode.

Going offline mode

Now refresh the same page again. and voila!! you will see layout of the website even in offline mode. No more Dinosaur on your page! Isn’t that cool?

Congratulations !! You have converted your Django website in progressive web app. But wait! Journey doesn’t end here. We can’t see any feeds in offline mode. Don’t worry! IndexedDB got you covered. We will cover IndexedDB operations to store feeds and serve them to user in offline mode in the next part.

Hope you have enjoyed the post. Thank you for reading.

If you are facing any issues refer: GitHub link of the project.

Part 2: Convert Django Website to a Progressive Web App [Part 2/2]