{{announcement.body}}
{{announcement.title}}

Django and React Single Page Application Development - Part 1

DZone 's Guide to

Django and React Single Page Application Development - Part 1

In this article, we begin a three-part series on how to create a SPA with a React-based frontend and Django and GraphQL on the server-side.

· Web Dev Zone ·
Free Resource

Introduction

In Pixly, we are using Django as our backend due to the excellent data science libraries and the great community in the Python ecosystem. However, when we have decided to make the frontend app as a single-page-application with React, we faced many difficulties. We hope that our tutorial will help newcomers a bit for solving their future problems.

Requirements

People who follow this tutorial should have at least an elementary level of knowledge about Python and a basic level of knowledge Django framework. Also, the basic level of Javascript and React is a must.

This tutorial series is planned to be made of three parts:

  1. Django backend.
  2. Django GraphQL API.
  3. React frontend and bundling the client app with Webpack.

The Project Description

We will make a stupidly simple single page application written with React that will communicate with our Django backend via a GraphQL API. The React app will be written from scratch with webpack. The create-react-app boilerplate will not be used.

There are a few options to make Django and React integrated in production:

  1. You may run two servers, one is Django backend and one for Node backend server. This is not ideal because of the costs associated with running two different servers.
  2. You may use serverless architecture, so you only pay for the functions that are triggered by client-side and query your database with it.
  3. You can run a Django backend server that will respond to our frontend application’s requests. This will be our approach in this series.
You may also like: Python Django Tutorial for Beginners.

Our frontend application will run on our users' browsers. All the frontend requests and logic will be done by the browser with a React JavaScript application.

Our project will not be an isomorphic application. Therefore, we need an API that will be used for the communication of Python backend and JavaScript frontend. We have two options for that; REST and GraphQL. We will use GraphQL. Our frontend and backend will use Apollo GraphQL and the Graphene framework respectively.

Maybe it is not the best solution, but we will use two servers in development. In production, we will use only one. Our bundled frontend app will not need a server.

Step 0: Configuring Environment

Note: If you choose to use your existing Python environment, you can skip this part and go to step 1.

This tutorial was written on a computer with Ubuntu 18.04 operating system. The default Python interpreter is Python 3.6.x. Due to the need for a clean environment, Python 3.8 will be installed, and the virtual environment will be built on it.

Shell




x
29


1
#<---Install python 3.8--->
2
cd /opt
3
sudo wget <https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz>
4
 
          
5
#extract the source
6
sudo tar xzf Python-3.8.0.tgz
7
 
          
8
cd Python-3.8.0
9
sudo ./configure --enable-loadable-sqlite-extensions
10
 
          
11
#use altinstall to prevent overriding your existing python environment
12
sudo make altinstall
13
 
          
14
#check version of python
15
python3.8 --version
16
# print Python 3.8.0
17
 
          
18
# <---Create Virtual Environment--->
19
 
          
20
# create virtual environment folder
21
cd ~/
22
mkdir venv
23
 
24
# create python 3.8 virtual environment name djr-venv
25
python3.8 -m venv ~/venv/djr-venv
26
 
          
27
# activate it
28
source ~/venv/djr-venv/bin/activate
29
# you can deactivate it with deactivate command



Create a Django Project

Step 1: Install Dependencies

Shell




xxxxxxxxxx
1


 
1
# <--- Create Django Project --->
2
 
          
3
# We will create the project in the Blog folder 
4
# with a name djr
5
 
          
6
# install our dependencies
7
pip install ipython django django_extensions django-cors-headers "graphene-django>=2.0" 



Step 2: Create a Django Project

Shell




xxxxxxxxxx
1
11


1
#start a django project
2
django-admin startproject djr
3
 
          
4
# change directory
5
cd djr
6
 
          
7
# create templates directory
8
mkdir templates
9
 
          
10
# create static folder
11
mkdir static



Step 3: Create a New Django App

Now, we can create our app in order to create database models.

Shell




xxxxxxxxxx
1


1
# create our app and activate it on the settings.py
2
python manage.py startapp items



Step 4: Configure Django Settings

Update your setting file according to this.

Python




xxxxxxxxxx
1
58


1
INSTALLED_APPS = [
2
    'django.contrib.admin',
3
    'django.contrib.auth',
4
    'django.contrib.contenttypes',
5
    'django.contrib.sessions',
6
    'django.contrib.messages',
7
    'django.contrib.staticfiles',
8
 
          
9
    "django_extensions",# New! (useful extension)
10
    'graphene_django',  # New! (for graphql communication)
11
    'corsheaders',      # New! (for cors request in dev env)
12
    "items" # ---> New! (make our app will active)
13
]
14
 
          
15
# New
16
# for improved interactive shell
17
# add this
18
SHELL_PLUS = "ipython"
19
 
          
20
# allow webpack development server to make cross-request
21
CORS_ORIGIN_WHITELIST = (
22
    '<http://localhost:8080>',
23
)
24
GRAPHENE = {
25
    'SCHEMA': 'gql.schema.schema'
26
}
27
 
          
28
MIDDLEWARE = [
29
    'django.middleware.security.SecurityMiddleware',
30
    'corsheaders.middleware.CorsMiddleware', # New Add this
31
    'django.contrib.sessions.middleware.SessionMiddleware',
32
    'django.middleware.common.CommonMiddleware',
33
    'django.middleware.csrf.CsrfViewMiddleware',
34
    'django.contrib.auth.middleware.AuthenticationMiddleware',
35
    'django.contrib.messages.middleware.MessageMiddleware',
36
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
37
]
38
 
          
39
TEMPLATES = [
40
    {
41
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
42
        'DIRS': (os.path.join(BASE_DIR, 'templates'),), # New
43
        'APP_DIRS': True,
44
        'OPTIONS': {
45
            'context_processors': [
46
                'django.template.context_processors.debug',
47
                'django.template.context_processors.request',
48
                'django.contrib.auth.context_processors.auth',
49
                'django.contrib.messages.context_processors.messages',
50
            ],
51
        },
52
    },
53
]
54
 
          
55
#New 
56
STATICFILES_DIRS = (
57
    os.path.join(BASE_DIR, 'static'),
58
)



Now, the general structure of the directory should look like this:

Directory structure

Directory structure

Step 5: Run the Django Server

Before starting our project, we should first make a database migration.

Shell




xxxxxxxxxx
1


 
1
# create migration for django-orm
2
python manage.py migrate



Now, we can start our project and see what happens.

Shell




xxxxxxxxxx
1


 
1
# run server
2
python manage.py runserver



Development server running

Development server running

Now, Our Django development server is ready.

You can go to the URL address of http://127.0.0.1:8000/ and verify that it is working.

Django default display

Django default display

After then, you can stop the server by pressing CTRL + C.

Step 6: Create the Movie App

We will create a movie model with basic fields that a movie should have. Before that, we should give some information about the field choices.

Why is there a URL field for poster rather than image field?

Because serving static files in production is out of our scope, we decide to use only the URL field. Fetching the image from remote and then saving it to our production storage is a topic for another post. Due to this, we will save only the poster's URL, not the poster itself as an image file. Also, sending static files like images is not a good approach. We will send the exact URL of an image to the user. Then, the user's browser fetches the image from the URL.

What is slug and why should it be unique?

When browsing on Pixly, if you open  The Matrix movie page, you will see that your address bar will be: https://pixly.app/movie/the-matrix-1999. The last part of the URL is the slug of The Matrix movie, which acts as an identifier which makes the URL distinctive from other movie pages. In the GraphQL part of the tutorial, you will see that this slug will be used as a query parameter, meaning that database queries will be done according to slug. Therefore, it should be unique.

We can also choose the movie id as a URL identifier, but it's clear that the URL will not be a human-readable address. Moreover, search engine indexing and ranking is a vital part of any website targeting new users. Readable URL addresses are good for users themselves and also suggested by search engine guides. For example, the Google webmaster guideline recommends using clean and concise URL structures. Let's make our model.

Let's open the items/models.py file.

Python




xxxxxxxxxx
1
18


1
# items.models
2
from django.db import models
3
 
          
4
# Create your models here.
5
class Movie(models.Model):
6
    id = models.IntegerField(primary_key=True)
7
    name = models.CharField(max_length=100)
8
    year = models.IntegerField(null=True)
9
    summary = models.TextField(max_length=5000,null=True)
10
    poster_url = models.URLField(blank=True, null=True)
11
    slug = models.SlugField(
12
                max_length=50, null=True,blank =True, unique=True)
13
 
          
14
    class Meta:
15
        ordering = ["-year"]
16
 
          
17
    def __str__(self):
18
        return self.name



Migrate again in order to make database arrangements for our new model.

Shell




xxxxxxxxxx
1


1
python manage.py makemigrations
2
python manage.py migrate



Step 7: Populating Database With Initial Data

There is no movie record currently in our database. We will provide a small initial data to create some movie records. All the data is provided by the community-built The Movie Database (TMDb).

First, create a class method in order to import initial data.

Python




xxxxxxxxxx
1
17


 
1
# items.models
2
 
          
3
class Movie(models.Model):
4
        """
5
            ... Model is truncated
6
        """
7
 
          
8
#<-----Add this class method------>
9
    @classmethod
10
    def import_records(cls, record_list):
11
        for record in record_list:
12
            # create record if id is not exist
13
            if not Movie.objects.filter(id=record.get("id")).exists():
14
                new_movie = cls.objects.create(**record)
15
            else:
16
                print(f"Id:{record.get('id')} is already exist.")
17
        print("Import operation done successfully")



Then, get the initial data file from GitHub repo and set the initial_data.py file in the utils folder. The directories and the initial data looks like this.

Initial data

Normally, we would have an open Django shell. However, shell_plus, which is provided by the django_extensions package, is more functional, so we will use this.

Shell




x


1
# normally we use this command
2
# python manage.py shell 
3
# However django_extensions shell is more functional
4
# it preimports all apps we created
5
 
          
6
# open interactive shell 
7
python manage.py shell_plus


Python




xxxxxxxxxx
1
15


 
1
# django interactive shell
2
# let's first check our database for movie records
3
# and verify that it empty.
4
In [1]: Movie.objects.all()                                                                                       
5
Out[1]: <QuerySet []>
6
 
          
7
 
          
8
# import the list of records
9
In [2]: from utils.initial_data import initial_data
10
 
          
11
# create records in the database
12
In [2]: Movie.import_records(initial_data)
13
#Import operation done successfully
14
 
          
15
#Successfully imported our initial data



Our model and database are ready. You can close the shell with the quit command.

In the next part, we will create our API with Python's GraphQL framework, Graphene, and its Django package graphene-django.


Further Reading

Topics:
web dev ,react ,javascript ,python django tutorial ,django framework ,graphql api

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}