Integrate React with Django: The Best Full-Stack Web Integration

Vaibhav Shukla
JavaScript in Plain English
11 min readJul 22, 2021

--

django and react with MRVAIBH
source: codingforentrepreneurs

Introduction

React and Django are the two MOST (when I say that, I mean that) popular frameworks out there, which are heavily used in the production by so many popular websites (including Medium itself).

Now, if you have come here, then it means you know how these frameworks work in a nutshell. If not, then stop reading this right away.

So let’s start, there are many approaches to integrate React and Django. Though there is no “official” way to do this of course. This is my approach, which I personally feel can be counted among best practices.

In this one, we will work on React and Django separately, and at the end, for production, we can run npm run build (so as to bundle the entire React app into a single folder), which can be then served to Django to render.

Sounds like a plan? 😇

Okay, so with no setup, create a new folder ‘DJREACT’.
(Assuming that you already have Python and Node.js installed)

Directory Structure of django and react with MRVAIBH
Directory structure

React Frontend Setup

Create a new folder frontend , and run npx create-react-app frontend (you can edit this name later in package.json file)

We also need Axios to work with API that we will create later in the backend

npm install axios

Open package.json and add this

{
"name": "djreact",
...
"proxy": "http://localhost:8000",
"homepage": "/dist",
...
}

> 1st line → name: Renaming the project (doesn’t make any difference)

> 2nd line → proxy: It will help in tunneling API requests to http://localhost:8000 where the Django application will handle them, so we can simplify writing the requests like this in React:

axios.get("/webapi/accounts/")

Instead of this:

axios.get("http://localhost:8000/webapi/accounts/")

> 3rd line → homepage: So that all the static files in the bundled react project, which is in the build folder can match the URLPATTERN of Django (must be same as STATIC_URL variable of settings.py in Django)

Now use `Axios` (npm package), to communicate with Django backend via API endpoints

Here’s a snippet on how to use Axios:

handleSubmit = item => {
this.toggle();
if (item.id) {
axios
.put(`http://localhost:8000/webapi/accounts/${item.id}/`, item)
.then(res => this.refreshList());
return;
}
axios
.post("http://localhost:8000/webapi/accounts/", item)
.then(res => this.refreshList());
};
handleDelete = item => {
axios
.delete(`http://localhost:8000/webapi/accounts/${item.id}`)
.then(res => this.refreshList());
};

Run npm start to run the app and it should work.

Fix Django’s CSRF token verification conflict

The built-in CSRF protection provided by Django is very useful to protect your server from malicious websites that can exploit your visitor browser to attack you. However, when using modern JavaScript libraries you will need to handle CSRF differently.

Edit src/App.js in frontend

import axios from 'axios';axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'

I know, I’m leaving most of the Axios part on you because it can be done easily. Link to tutorial

Output

Django Backend Setup

The only purpose Django will serve is to create an API that can be used by React to communicate with the database.

Creating Virtual Environment for Python (optional)

Open the command-line shell in ‘DJREACT’ and run $ pip install pipenv

$ pipenv shell (this will create a virtual environment)

This step is optional, though it is recommended to have a Virtual Env, as you will probably push your code somewhere in the future.

Actual Django installation

I recommend you to first read Django Rest Framework docs

$ pipenv install django djangorestframework djangorestframework-simplejwt django-cors-headers
$ django-admin startproject djreact .
$ python manage.py startapp accounts
$ python manage.py migrate
$ python manage.py createsuperuser --username admin
Email: ......
Password: ........

Edit settings.py in djreact (main)

These settings are as important as they appear. Especially that DRF Authentication one, it configures the permission of your API for the entire app, but you can set it manually for every view as well.

But remember, these are NOT production settings, there will be some situations where you have to change some of the variables.

ALLOWED_HOSTS = ['localhost', 'localhost:3000']CORS_ORIGIN_WHITELIST = [
'http://localhost:3000',
]
INSTALLED_APPS = [
...
# Third party apps
'rest_framework',
'corsheaders',

# My apps
'accounts.apps.AccountsConfig',
]
# DRF Authentication Scheme <- you can click here :)# set permission according to your requirements
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES’: [
'rest_framework_simplejwt.authentication.JWTAuthentication’,
],
'DEFAULT_PERMISSION_CLASSES’: [
'rest_framework.permissions.DjangoModelPermissions’,
'rest_framework.permissions.IsAdminUser'
]
}
MIDDLEWARE = [
...,
'corsheaders.middleware.CorsMiddleware',
...,
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [ BASE_DIR / 'frontend' ],
...
},
},
]
...STATIC_URL = '/dist/'# Extra places for collectstatic to find static files.
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [
BASE_DIR / 'frontend/build',
]

Now run these commands to make sure that all tables are created.

$ python manage.py makemigrations
$ python manage.py migrate

In ./accounts folder

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks.

Create serializers.py in accounts

from rest_framework import serializers
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'

You already know what views are, right? No?? what are you doing here then?

Edit views.py in accounts

from rest_framework import viewsetsfrom django.contrib.auth.models import User
from .serializers import UserSerializer
# To make password encryption
from django.contrib.auth.hashers import make_password
# API view for django.contrib.auth.models.User
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# it takes recent instance from serialzer and uses `make_password` to encrypt
def perform_create(self, serializer):
# Hash password but passwords are not required
if ('password' in self.request.data):
password = make_password(self.request.data['password'])
serializer.save(password=password)
else:
serializer.save()
def perform_update(self, serializer):
# Hash password but passwords are not required
if ('password' in self.request.data):
password = make_password(self.request.data['password'])
serializer.save(password=password)
else:
serializer.save()

Edit urls.py in accounts

from django.urls import path, includefrom rest_framework.routers import DefaultRouterfrom . import views# Registering Rest-API routes for Accounts
router = DefaultRouter()
router.register(r'user', views.UserViewSet, 'user')
urlpatterns = [
path('', include(router.urls), name='accounts_api'),
]

In ./djreact (main) project folder

Create views.py in djreact (main)

from django.shortcuts import renderdef index(request):
return render(request, 'build/index.html')

NOTE: You can change “build” to “public” in the development, for that you need to have webpack.config.js and .babelrcconfigured to convert all the src code in one js file.

Read more about webpack and babel

Edit urls.py in djreact (main)

Finally, all the URLs (from other apps) are included in this main one
Notice we are also using “auth” for rest_framework, from where we can authorize the user to use our webapi.

from django.contrib import admin
from django.urls import path, include
# Static files
from . import settings
from django.conf.urls.static import static
# DRF Simple JWT library
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
from . import viewsurlpatterns = [
path('admin/', admin.site.urls),
path('', views.index),

# For REST login
path('auth/', include('rest_framework.urls'), name='rest_login'),
# For accessing Token to authenticate
path('get-auth-token/', TokenObtainPairView.as_view(), name='get_auth_token'),
path('refresh-auth-token/', TokenRefreshView.as_view(), name='refresh_auth_token'),
path('verify-auth-token/', TokenVerifyView.as_view(), name='verify_auth_token'),

# API for other apps
path('webapi/accounts/', include('accounts.urls'), name='webapi_accounts'),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Output

Deployment

Just run npm build and it will bundle an optimized React application into the build folder.

Now you only need to run python manage.py runserver to run the entire app.

Now technically you are just using a Django application. But who knows that you have created your full frontend in React JS. 😎

To follow full deployment to the server (which is easiest in Heroku), check this out Heroku Django app deployment.

But I recommend don’t just depend on Heroku, try to learn the concept behind it, don’t just copy-paste the commands.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Join our community Discord.

django and react with MRVAIBH
source: codingforentrepreneurs

Introduction

React and Django are the two MOST (when I say that, I mean that) popular frameworks out there, which are heavily used in the production by so many popular websites (including Medium itself).

Now, if you have come here, then it means you know how these frameworks work in a nutshell. If not, then stop reading this right away.

So let’s start, there are many approaches to integrate React and Django. Though there is no “official” way to do this of course. This is my approach, which I personally feel can be counted among best practices.

In this one, we will work on React and Django separately, and at the end, for production, we can run npm run build (so as to bundle the entire React app into a single folder), which can be then served to Django to render.

Sounds like a plan? 😇

Okay, so with no setup, create a new folder ‘DJREACT’.
(Assuming that you already have Python and Node.js installed)

Directory Structure of django and react with MRVAIBH
Directory structure

React Frontend Setup

Create a new folder frontend , and run npx create-react-app frontend (you can edit this name later in package.json file)

We also need Axios to work with API that we will create later in the backend

npm install axios

Open package.json and add this

{
"name": "djreact",
...
"proxy": "http://localhost:8000",
"homepage": "/dist",
...
}

> 1st line → name: Renaming the project (doesn’t make any difference)

> 2nd line → proxy: It will help in tunneling API requests to http://localhost:8000 where the Django application will handle them, so we can simplify writing the requests like this in React:

axios.get("/webapi/accounts/")

Instead of this:

axios.get("http://localhost:8000/webapi/accounts/")

> 3rd line → homepage: So that all the static files in the bundled react project, which is in the build folder can match the URLPATTERN of Django (must be same as STATIC_URL variable of settings.py in Django)

Now use `Axios` (npm package), to communicate with Django backend via API endpoints

Here’s a snippet on how to use xios:

handleSubmit = item => {
this.toggle();
if (item.id) {
axios
.put(`http://localhost:8000/webapi/accounts/${item.id}/`, item)
.then(res => this.refreshList());
return;
}
axios
.post("http://localhost:8000/webapi/accounts/", item)
.then(res => this.refreshList());
};
handleDelete = item => {
axios
.delete(`http://localhost:8000/webapi/accounts/${item.id}`)
.then(res => this.refreshList());
};

Run npm start to run the app and it should work.

Fix Django’s CSRF token verification conflict

The built-in CSRF protection provided by Django is very useful to protect your server from malicious websites that can exploit your visitor browser to attack you. However, when using modern JavaScript libraries you will need to handle CSRF differently.

Edit src/App.js in frontend

import axios from 'axios';axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'

I know, I’m leaving most of the Axios part on you because it can be done easily. Link to tutorial

Output

Django Backend Setup

The only purpose Django will serve is to create an API that can be used by React to communicate with the database.

Creating Virtual Environment for Python (optional)

Open the command-line shell in ‘DJREACT’ and run $ pip install pipenv

$ pipenv shell (this will create a virtual environment)

This step is optional, though it is recommended to have a Virtual Env, as you will probably push your code somewhere in the future.

Actual Django installation

I recommend you to first read Django Rest Framework docs

$ pipenv install django djangorestframework djangorestframework-simplejwt django-cors-headers
$ django-admin startproject djreact .
$ python manage.py startapp accounts
$ python manage.py migrate
$ python manage.py createsuperuser --username admin
Email: ......
Password: ........

Edit settings.py in djreact (main)

These settings are as important as they appear. Especially that DRF Authentication one, it configures the permission of your API for the entire app, but you can set it manually for every view as well.

But remember, these are NOT production settings, there will be some situations where you have to change some of the variables.

ALLOWED_HOSTS = ['localhost', 'localhost:3000']CORS_ORIGIN_WHITELIST = [
'http://localhost:3000',
]
INSTALLED_APPS = [
...
# Third party apps
'rest_framework',
'corsheaders',

# My apps
'accounts.apps.AccountsConfig',
]
# DRF Authentication Scheme <- you can click here :)# set permission according to your requirements
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES’: [
'rest_framework_simplejwt.authentication.JWTAuthentication’,
],
'DEFAULT_PERMISSION_CLASSES’: [
'rest_framework.permissions.DjangoModelPermissions’,
'rest_framework.permissions.IsAdminUser'
]
}
MIDDLEWARE = [
...,
'corsheaders.middleware.CorsMiddleware',
...,
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [ BASE_DIR / 'frontend' ],
...
},
},
]
...STATIC_URL = '/dist/'# Extra places for collectstatic to find static files.
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [
BASE_DIR / 'frontend/build',
]

Now run these commands to make sure that all tables are created.

$ python manage.py makemigrations
$ python manage.py migrate

In ./accounts folder

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks.

Create serializers.py in accounts

from rest_framework import serializers
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'

You already know what views are, right? No?? what are you doing here then?

Edit views.py in accounts

from rest_framework import viewsetsfrom django.contrib.auth.models import User
from .serializers import UserSerializer
# To make password encryption
from django.contrib.auth.hashers import make_password
# API view for django.contrib.auth.models.User
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# it takes recent instance from serialzer and uses `make_password` to encrypt
def perform_create(self, serializer):
# Hash password but passwords are not required
if ('password' in self.request.data):
password = make_password(self.request.data['password'])
serializer.save(password=password)
else:
serializer.save()
def perform_update(self, serializer):
# Hash password but passwords are not required
if ('password' in self.request.data):
password = make_password(self.request.data['password'])
serializer.save(password=password)
else:
serializer.save()

Edit urls.py in accounts

from django.urls import path, includefrom rest_framework.routers import DefaultRouterfrom . import views# Registering Rest-API routes for Accounts
router = DefaultRouter()
router.register(r'user', views.UserViewSet, 'user')
urlpatterns = [
path('', include(router.urls), name='accounts_api'),
]

In ./djreact (main) project folder

Create views.py in djreact (main)

from django.shortcuts import renderdef index(request):
return render(request, 'build/index.html')

NOTE: You can change “build” to “public” in the development, for that you need to have webpack.config.js and .babelrcconfigured to convert all the src code in one js file.

Read more about webpack and babel

Edit urls.py in djreact (main)

Finally, all the URLs (from other apps) are included in this main one
Notice we are also using “auth” for rest_framework, from where we can authorize the user to use our webapi.

from django.contrib import admin
from django.urls import path, include
# Static files
from . import settings
from django.conf.urls.static import static
# DRF Simple JWT library
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
from . import viewsurlpatterns = [
path('admin/', admin.site.urls),
path('', views.index),

# For REST login
path('auth/', include('rest_framework.urls'), name='rest_login'),
# For accessing Token to authenticate
path('get-auth-token/', TokenObtainPairView.as_view(), name='get_auth_token'),
path('refresh-auth-token/', TokenRefreshView.as_view(), name='refresh_auth_token'),
path('verify-auth-token/', TokenVerifyView.as_view(), name='verify_auth_token'),

# API for other apps
path('webapi/accounts/', include('accounts.urls'), name='webapi_accounts'),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Output

Deployment

Just run npm build and it will bundle an optimized React application into the build folder.

Now you only need to run python manage.py runserver to run the entire app.

Now technically you are just using a Django application. But who knows that you have created your full frontend in React JS. 😎

To follow full deployment to the server (which is easiest in Heroku), check this out Heroku Django app deployment.

But I recommend don’t just depend on Heroku, try to learn the concept behind it, don’t just copy-paste the commands.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Join our community Discord.

--

--