Integration a React app into Django project
Intoduction
In this article, I will show you how to integrate a React application into a Django project. The idea is that Django renders its templates, and React modifies them as needed
If you want to skip the basic setup and move on to the React integration part.
Also you can download a ready-made project for it.
Create a Django project
We will start by creating a root directory for our project.
mkdir SearchResultParser
cd SearchResultParser
Now, create and activate a virtual environment.
python -m venv .venv
source ./.venv/Scripts/activate
python -m venv .venv
.venv\Scripts\Activate.ps1
After activating a virtual environment, we have to install django package and start a new project. Letβs call it a Website.
pip install django
django-admin startproject Website
cd Website
If everything is done right, we will successfully launch a project. Just like that:
./manage.py runserver
Create a Backend app
Now, we need to install a couple of new Python packages to configure our Backend app.
django-cors-headers: for enabling so-called Cross-Origin Resource Sharing (CORS) for communication between React app and Django API.
djangorestframework: an Django app that allows us to build an API for further use.
pip install djangorestframework django-cors-headers
Create a Backend app
./manage.py startapp Backend
Edit the settings.py file using your favorite text editor. In my case, it is NeoVim. We will link the newly created app and those that we installed earlier.
nvim Backend/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
'rest_framework',
'Backend.apps.BackendConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware',
]
Add this at the end of settings.py file:
CORS_ORIGIN_WHITELIST = [
'http://localhost:3000'
]
For now, create a urls.py file:
touch Backend/urls.py
Get-Item Backend/urls.py
Paste the next content in the urls.py file in the Website folder by this:
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from Backend import views
router = routers.DefaultRouter()
router.register(r'results', views.BackendModelView, 'result')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
]
Here we imported routers for rest_framework and views from our Backend app and then included them into urlpatterns.
The next thing we will do is to create a placeholder model for now.
nvim Backend/models.py
from django.db import models
class BackendModel(models.Model):
title = models.CharField(max_length=120)
description = models.TextField()
def _str_(self):
return self.title
And link our model with the default Django admin app.
nvim Backend/admin.py
from django.contrib import admin
from .models import BackendModel
class BackendModelAdmin(admin.ModelAdmin):
list_display = ('title', 'description')
admin.site.register(BackendModel, BackendModelAdmin)
To work, the rest framework needs to have a serializer class. What he does is convert Django models into JSON files for us.
touch Backend/serializers.py
Get-Item Backend/serializers.py
nvim Backend/serializers.py
from rest_framework import serializers
from .models import BackendModel
class BackendModelSerializer(serializers.ModelSerializer):
class Meta:
model = BackendModel
fields = ('id', 'title', 'description')
The last thing we need to do is create a specific view class for BackendModel.
nvim Backend/views.py
from django.shortcuts import render
from rest_framework import viewsets
from .serializers import BackendModelSerializer
from .models import BackendModel
class BackendModelView(viewsets.ModelViewSet):
serializer_class = BackendModelSerializer
queryset = BackendModel.objects.all()
At the end, create all migrations and apply them.
./manage.py makemigrations
./manage.py migrate
Also create a super user to gain access to the database.
./manage.py createsuperuser
Create a Frontend app
It is time for the Frontend app. This app is going to contain our React app. But first, we need to create, link, and prepare this app.
./manage.py startapp Frontend
nvim Website/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
'rest_framework',
'Backend.apps.BackendConfig',
'Frontend.apps.FrontendConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware',
]
Create an urls.py file for the Frontend app and paste the next content.
touch Frontend/urls.py
Get-Item Frontend/urls.py
nvim Frontend/urls.py
from django.urls import path
from .views import main
urlpatterns = [
path('', main, name='main')
]
The same, we need to create the main function. It is a placeholder; in the future, this function is going to be deleted.
nvim Frontend/views.py
from django.shortcuts import render
def main(request):
return render(request, 'Frontend/app.html')
To render something, we need to create an HTML file.Β
mkdir Frontend/templates
mkdir Frontend/templates/Frontend
touch Frontend/templates/Frontend/app.html
Get-Item Frontend/templates/Frontend/app.html
And include the created earlier urls.py file in the Frontend directory in the main urls.py file in the Website directory.
nvim Website/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from Backend import views
router = routers.DefaultRouter()
router.register(r'results', views.BackendModelView, 'result')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
path('', include('Frontend.urls')),
]
React installation
Now it is time for React installation. It is relatively easy if you know what to install ;). Go to the Frontend directory and create a static directory:
cd Frontend
mkdir static
To store all js bundles
mkdir static/js
To store all images
mkdir static/img
To store all css files
mkdir static/css
To store all react components
mkdir src
mkdir src/components
At this step, the Frontend app is ready, and the last thing to do is to create and configure the React app.
npm init -y
Install initial packages, one by one:
webpack to bundle all of our JS code
babel for translating all of our JS and CSS code into friendly types for each browser.
react for developing all of our frontend parts of the website
npm i webpack webpack-cli --save-dev ;
npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev ;
npm i react react-dom --save-dev ;
npm install @babel/plugin-proposal-class-properties ;
npm install react-router-dom;
Weβre still in the Frontend directory. Create a config file:
touch babel.config.json
Get-Item babel.config.json
And then paste it:
{
Β Β "presets": [
Β Β Β Β [
Β Β Β Β Β Β "@babel/preset-env",
Β Β Β Β Β Β {
Β Β Β Β Β Β Β Β "targets": {
Β Β Β Β Β Β Β Β Β Β "node": "10"
Β Β Β Β Β Β Β Β }
Β Β Β Β Β Β }
Β Β Β Β ],
Β Β Β Β "@babel/preset-react"
Β Β ],
Β Β "plugins": ["@babel/plugin-proposal-class-properties"]
}
Configure a webpack packet, but first do not forget to create a config file:
touch webpack.config.js
Get-Item webpack.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
Β entry: "./src/index.js",
Β output: {
Β Β path: path.resolve(__dirname, "./static/js"),
Β Β filename: "[name].js",
Β },
Β module: {
Β Β rules: [
Β Β Β {
Β Β Β Β test: /\.js$/,
Β Β Β Β exclude: /node_modules/,
Β Β Β Β use: {
Β Β Β Β Β loader: "babel-loader",
Β Β Β Β },
Β Β Β },
Β Β ],
Β },
Β optimization: {
Β Β minimize: true,
Β },
Β plugins: [
Β Β new webpack.DefinePlugin({
Β Β Β "process.env": {
Β Β Β Β // This has effect on the react lib size
Β Β Β Β NODE_ENV: JSON.stringify("production"),
Β Β Β },
Β Β }),
Β ],
};
Configuring package.json file.
Paste this into scripts list:
{
Β "name": "frontend",
Β "version": "1.0.0",
Β "main": "index.js",
Β "scripts": {
Β Β "dev": "webpack --mode development --watch",
Β Β "prod": "webpack --mode production"
Β },
Β "keywords": [],
Β "author": "",
Β "license": "ISC",
Β "description": "",
Β "devDependencies": {
Β Β "@babel/core": "^7.25.2",
Β Β "@babel/preset-env": "^7.25.3",
Β Β "@babel/preset-react": "^7.24.7",
Β Β "babel-loader": "^9.1.3",
Β Β "react": "^18.3.1",
Β Β "react-dom": "^18.3.1",
Β Β "webpack": "^5.93.0",
Β Β "webpack-cli": "^5.1.4"
Β },
Β "dependencies": {
Β Β "@babel/plugin-proposal-class-properties": "^7.18.6",
Β Β "react-router-dom": "^6.25.1"
Β }
}
Creating first react component
After everything is set up, letβs write some React code. In a Frontend/src folder, create an index.js, and in Frontend/src/components, create an App.js file.
touch src/index.js;
touch src/components/App.js;
Get-Item src/index.js
Get-Item src/components/App.js
Then paste this example code into App.js
import React from 'react';
import { createRoot } from 'react-dom/client';
const App = () => {
Β Β return Rendered by Django, cooked by React
;
};
export default App;
const container = document.getElementById('app');
const root = createRoot(container);
root.render( );
We need to include the App component in index.js. Paste this:
import App from './components/App';
At the end, we need to paste this example code into the app.html file. His location is Frontend/templates/Frontend/app.html.
{% load static %}
Β Β
Β Β
Β Β React with Django
Β Β
Β Β
Everything is set up. Now, letβs test it. Firstly, run django server:
./manage.py runserver
Secondly start React app
npm run dev
If you did all right, you will see something like this.
Conclusion
All begins with Djangoβs rendered template. After this, React is going to find a div by id βappβ and render our h1 tag. Now we have a full-stack app that is ready to be developed.
If you skipped all of the above and just want a ready-to-use solution, here it is. An archive with preconfigured folder structure and precalculated dependencies. All you need to do is set up a virtual environment (install all required Python packages) for the downloaded folder and install the required NPM packages in the Frontend app.
In the next article, I will show you the basic layout for a website and what it is going to look like.
Common errors, bugs and mistakes
-
Incorrect Project StructureMistake: Not organizing the project directory properly, leading to confusion and difficulties in managing both React and Django codebases.Solution: Maintain a clear and logical directory structure. Keep frontend and backend code in separate directories.
-
Ignoring CORS IssuesMistake: Overlooking Cross-Origin Resource Sharing (CORS) settings, which can lead to blocked requests.Solution: Configure your Django backend to handle CORS. Use django-cors-headers to allow specific origins.
-
Inconsistent Environment ConfigurationMistake: Having conflicting or inconsistent environment configurations, leading to issues in development and production builds.Solution: Ensure that environment variables are consistently defined. Use tools like dotenv for managing environment variables in both React and Django.
-
Incorrectly Handling Static FilesMistake: Misconfiguring static file handling, which can lead to issues in serving React assets in Django.Solution: Properly configure Django to serve static files and ensure React assets are placed in a directory Django can serve.
-
Ignoring Client-Side Routing ConflictsMistake: Ignoring potential conflicts between Django's and React Router's routing mechanisms, leading to broken links or incorrect routing.Solution: Delegate client-side routing to React Router and ensure Django serves the React app for all relevant routes.
2