DEV Community

Cover image for Deploying a Django project on AWS Lambda using Serverless (Part 4)
Vadym Khodak
Vadym Khodak

Posted on • Edited on • Originally published at vadymkhodak.com

Deploying a Django project on AWS Lambda using Serverless (Part 4)

As I promised in my previous blog post Deploying a Django project on AWS Lambda using Serverless (Part 3), I'd like to show you how to add a React.JS client to a Django project and deploy it with Django on AWS Lambda using Serverless.

BLUF

Django framework allows you to build a client using Django templates, but there are a lot of cases when this is not enough. Business requirements for the client-side of your application could require adding more complex logic on the client-side. In these cases, we will not be able to solve business problems without a JavaScript web framework (React.JS, Vue.JS, Angular, etc). I'd like to show you how to build a simple React.JS client and integrate it with a Django project using axios library on the client-side and Django REST Framework on the server-side.

With this approach, I will build a React.JS client with a domain name of CloudFront distribution as a PUBLIC_URL and store it on AWS S3 bucket together with Django static files. Then, I add the built index.html file with React.JS app to Django templates folder and deploy it with the Django project on AWS Lambda.

Getting started

I've already described how to create a Django project and deploy it on AWS Lambda using Serverless in my first blog post of this series. I will use that project to get started.

Let's go through this process step by step:

git clone https://github.com/vadym-khodak/django-aws-lambda cd django-aws-lambda 
Enter fullscreen mode Exit fullscreen mode
  • Follow instructions from this blog post to run the Django server (install requirements, configure environment variables using .env, apply migrations, create a superuser, collect static, run the server).

If everything works, you are ready to start working on the client.

Add React.JS client

In this part, I'll show how to create a simple React.JS client and integrate it with our Django project, but I'm sure that you can easily use Vue.JS (I'm not familiar with Angular) as steps pretty much the same.

There are many options to create React.JS client. I'm using react-scripts in this example.

npm install -g react-scripts 
Enter fullscreen mode Exit fullscreen mode
  • Use react-scripts to initialize a React.JS client
npm init react-app client 
Enter fullscreen mode Exit fullscreen mode
  • Check that React.JS client was built successfully
cd client npm run start 
Enter fullscreen mode Exit fullscreen mode

It will open your browser on localhost port 3000 and you will see a page like this:

image.png

Update Django project configuration

Let's update our Django configuration to render index.html file with React.JS client:

  • Add CLIENT_DIR environment variable to .env file:
CLIENT_DIR="client/build" 
Enter fullscreen mode Exit fullscreen mode
  • Update django_aws_lambda/urls.py file with the following code:
from django.contrib import admin from django.urls import path, include from django.views.generic import TemplateView urlpatterns = [ path('admin/', admin.site.urls), path('hello/', include('hello.urls')), path('', TemplateView.as_view(template_name="index.html"), {'resource': ''}), path('<path:resource>', TemplateView.as_view(template_name="index.html")), ] 
Enter fullscreen mode Exit fullscreen mode
  • Update STATICFILES_DIRS in django_aws_lambda/settings.py
STATICFILES_DIRS = [ str(ROOT_DIR / env('CLIENT_DIR', default='client/build')), str(ROOT_DIR / 'static'), ] 
Enter fullscreen mode Exit fullscreen mode

Check that our Django project can run the React.JS client

  • Build production React.JS client locally the following commands:
cd client export PUBLIC_URL=static/ npm run build cd .. 
Enter fullscreen mode Exit fullscreen mode
  • Collect static files by running the following command:
python manage.py collectstatic --no-input 
Enter fullscreen mode Exit fullscreen mode
  • Run this Django project locally (make sure that you have already applied migrations and created a superuser):
python manage.py runserver 
Enter fullscreen mode Exit fullscreen mode

image.png

It looks the same as we saw before by running npm run start in client folder. There are just a couple of differences - now it is run on port 8000 and it is run by our Django web server.

Make the React.JS client talk to the Django server.

First, we need to create an API endpoint to return some data from the server to the client. The easiest way to build REST API in Django is using Django REST framework project.

  • Install Django REST framework and add it to requirements.txt file
pip install djangorestframework 
Enter fullscreen mode Exit fullscreen mode
  • Create a new Django app called users by running the following command:
python manage.py startapp users 
Enter fullscreen mode Exit fullscreen mode
  • Update users/views.py file with the following code:
from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response @api_view(["GET"]) def get_current_user(request): return Response(status=status.HTTP_200_OK, data={"username": request.user.username}) 
Enter fullscreen mode Exit fullscreen mode

This is an endpoint that returns Response object with username (if the user is not authorized it will return an empty string as username)

  • Update users/urls.py file with the following code:
from django.urls import path from .views import get_current_user app_name = "users" urlpatterns = [ path("me/", view=get_current_user, name="get-current-user"), ] 
Enter fullscreen mode Exit fullscreen mode
  • Update our Django project configuration

Update django_aws_lambda/urls.py file with the following code:

from django.contrib import admin from django.urls import path, include from django.views.generic import TemplateView urlpatterns = [ path('admin/', admin.site.urls), path('hello/', include('hello.urls')), path('api/users/', include('users.urls')), path('', TemplateView.as_view(template_name="index.html"), {'resource': ''}), path('<path:resource>', TemplateView.as_view(template_name="index.html")), ] 
Enter fullscreen mode Exit fullscreen mode
  • Update INSTALLED_APPS in django_aws_lambda/settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hello', 'rest_framework', 'users', ] 
Enter fullscreen mode Exit fullscreen mode

Modifying React.JS client to send requests to the Django server

  • Install axios library:
cd client npm install axios -S 
Enter fullscreen mode Exit fullscreen mode

-S flag will add axios library to package.json file

  • Update client/src/App.js file with the following code:
import { useEffect, useState } from 'react'; import axios from 'axios'; import logo from './logo.svg'; import './App.css'; function App() { const loadUserDetails = async () => { const response = await axios.get('/api/users/me/'); return response.data; }; const [userData, setUserData] = useState(false); useEffect(() => { loadUserDetails().then((payload) => { setUserData(payload); }); }, []); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload.  </p>  <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a>  <h1>Hello, World!</h1>  <h2>I'm {(userData && userData.username) || 'Unknown User'}</h2> </header> </div> ); } export default App; 
Enter fullscreen mode Exit fullscreen mode
  • Build production optimized client by running the following command:
export PUBLIC_URL=static/ npm run build cd .. 
Enter fullscreen mode Exit fullscreen mode
  • Collect static files by running the following command:
python manage.py collectstatic --no-input 
Enter fullscreen mode Exit fullscreen mode
  • Run this Django project locally:
python manage.py runserver 
Enter fullscreen mode Exit fullscreen mode

Go to your browser, open this URL http://localhost:8000 and you will see a page like this:

image.png

But if you authorize using your superuser username and password you will see a page like this:

image.png

Deploying on AWS Lambda using Serverless

Prepare AWS infrastructure

I've already described how to prepare AWS infrastructure in my previous blog posts, so you can use one of the following approaches:

Update Serverless configuration

Add client folder to package.exclude to exclude it from deployment

Update URL in client/src/App.js file to be able to send requests to production server

 const response = await axios.get('/production/api/users/me/'); 
Enter fullscreen mode Exit fullscreen mode

Use Docker for deploying your Django project to AWS Lambda using Serverless

  • Prepare Amazon Linux 2 docker image with all the necessary dependencies:
docker run -it -v $(pwd):/root/src/ -v /Users/<your-username>/.aws:/root/.aws amazonlinux:latest bash # install the necessary Unix dependencies: yum install sudo -y sudo yum install -y gcc openssl-devel bzip2-devel libffi-devel wget tar sqlite-devel gcc-c++ make # install node.js version 14: curl -sL https://rpm.nodesource.com/setup_14.x | sudo -E bash - sudo yum install -y nodejs # install Python 3.8.7: cd /opt sudo wget https://www.python.org/ftp/python/3.8.7/Python-3.8.7.tgz sudo tar xzf Python-3.8.7.tgz cd Python-3.8.7 sudo ./configure --enable-optimizations sudo make altinstall sudo rm -f /opt/Python-3.8.7.tgz # create python and pip aliases: alias python='python3.8' alias pip='pip3.8' # update pip and setuptools: pip install --upgrade pip setuptools # install serverless: npm install -g serverless # move to project directory cd /root/src/ # install requirements inside docker container: pip install -r requirements.txt # set the necessary environment variables export DJANGO_SETTINGS_MODULE=django_react_aws_lambda.production export AWS_ACCESS_KEY_ID=<your-aws-access-key-id> export AWS_SECRET_ACCESS_KEY=<your-aws-secret-access-key> # migrate database changes python manage.py migrate # create a superuser in the database python manage.py createsuperuser # build React.JS client for AWS Lambda cd client npm install export PUBLIC_URL="https://<your-cloud-front-distribution>.cloudfront.net/static/" npm run build # copy `index.html` from `client/build` to `templates` cp build/index.html ../templates/index.html cd .. # collect static files to AWS S3 bucket python manage.py collectstatic --no-input # install serverless packages from package.json npm install # deploy your Django project to AWS Lambda using Serverless serverless deploy -s production 
Enter fullscreen mode Exit fullscreen mode

Now, your Django Project with React.JS client will be available at this URL:
https://<some-id>.execute-api.<your-aws-region>.amazonaws.com/production

Without authorized user:

image.png

With authorized user:

image.png

How it works

When you go to the Django project URL on your browser it will go to AWS API Gateway that will trigger AWS Lambda function with the Django WSGI server. The Django server will render index.html with React.JS app, the browser will use the domain name of the CloudFront distribution to get React.JS client from the AWS S3 bucket.

Final Words

In this blog post, we saw how to add the React.JS client to the Django project and deploy them on AWS Lambda using Serverless. There is a link to the GitHub repository (GitLab copy) with the code shown in this blog post.

It is the final blog post in this series. I showed just one of many ways to deploy a Django project on AWS Lambda, prepare AWS infrastructure, and add a React.JS client. You can find many other ways to do the same, it is up to you which approach to use.

Don't forget to follow me on Twitter @vadim_khodak or on LinkedIn so you do not miss the next posts.

Top comments (0)