Convert Django Website to a Progressive Web App [Part 1/2]
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:
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:
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.
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
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:
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:
Now open service workers from application tab and tick the 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]