Sitemap
8 min readFeb 16, 2023

Fullstack React — Django App

  • In this blog, we will learn, how to build a full-stack app in react and Django.
Press enter or click to view image in full size

The front-end

For building the front-end, we will use react.js.

  1. Firstly create a react app and name it frontendapp. Click here to learn more.
  2. Hoping that you have created a brand new react application.
  3. Install material ui , react-redux, reduxjs/toolkit and react-router-dom.

mui -> npm install @mui/material @emotion/react @emotion/styled

mui-icons -> npm install @mui/icons-material

react-redux -> npm i react-redux

reduxjs/toolkit -> npm i @reduxjs/toolkit

react-router-dom -> npm i react-router-dom@5

4. First of all we will define our routes. Inside App.js paste this code.

<main>
<Router initialEntries={["/home", "/finalpage"]}>
<Switch>
<Route path={"/"} exact>
<Redirect to={"/home"} />
</Route>
<Route path={"/home"} >
<CustomForm />
</Route>
<Route path={"/finalpage"} >
<FinalPage/>
</Route>
</Switch>
</Router>
</main>

We get Router, Switch and Route from react-router-dom.

<Route path={"/home"} > -> Path defines the url 
<CustomForm /> -> The component to be rendered with respect to path paramter given
</Route>
Overall App.js

import CustomForm from "./Components/CustomForm";
import {MemoryRouter as Router, Switch, Route, Redirect } from "react-router-dom";
import FinalPage from './Components/FinalPage'
function App() {
return (
<>
<main>
<Router initialEntries={["/home", "/finalpage"]}>
<Switch>
<Route path={"/"} exact>
<Redirect to={"/home"} />
</Route>
<Route path={"/home"} >
<CustomForm />
</Route>
<Route path={"/finalpage"} >
<FinalPage/>
</Route>
</Switch>
</Router>
</main>
</>
);
}

export default App;

Now we need to wrap everything inside BrowserRouter for the.

Inside index.js ->


root.render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>

);

5. Setting up the components.

Inside src create one folder “Components” and create CustomForm.js file

CustomForm.js

import React from "react";
import { Button, TextField } from "@mui/material";
import classes from "./CustomForm.module.css";
import { useState } from "react";
import AddIcon from "@mui/icons-material/Add";
import { getTenDigitRandomNumber } from "../Helper/utils";
import { useDispatch } from "react-redux";
import { userAction } from "../Redux/Store";
import { useHistory } from "react-router-dom";

function CustomForm() {
const dispatch = useDispatch();
const history = useHistory();
const [inputfields, setInputFields] = useState([
{ username: "", email: "", phonenumber: "", address: "" },
]);
const handleFormChange = (index, event) => {
let data = [...inputfields];
data[index][event.target.name] = event.target.value;
setInputFields(data);
};
const addUsers = () => {
let newUser = { username: "", email: "", phonenumber: "", address: "" };
setInputFields([...inputfields, newUser]);
};


const postToServer = async (data_to_be_sent) => {
const response = await fetch("http://127.0.0.1:8000/apis/v1/test/", {
method: "POST",
mode: "cors", // no-cors, *cors, same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data_to_be_sent),
});

const jsonData = await response.json();
dispatch(
userAction.updateUserDetails({
totaluser: jsonData.data.totalnumberofusers,
users: jsonData.data.users,
})
);
if (response.status === 200) {
history.replace("/finalpage");
}
};

const handleSubmit = (event) => {
event.preventDefault();
const data_to_be_sent = {
record_name: getTenDigitRandomNumber(),
users: inputfields,
};
postToServer(data_to_be_sent);
};

return (
<div>
<h2 className={classes.heading}>Form Demo</h2>
<form className={classes.customform} onSubmit={handleSubmit}>
{inputfields.map((input, index) => {
return (
<div
key={index}
style={{ display: "flex", flexDirection: "column" }}
>
<h3 style={{ paddingTop: "1%" }}>Data for user {index + 1}</h3>
<TextField
name="username"
value={input.username}
onChange={(e) => handleFormChange(index, e)}
className={classes.inputFields}
label={"Enter User Name"}
/>
<TextField
name="email"
type="email"
value={input.email}
onChange={(e) => handleFormChange(index, e)}
className={classes.inputFields}
label={"Enter Email"}
/>
<TextField
name="phonenumber"
type="number"
value={input.phone}
onChange={(e) => handleFormChange(index, e)}
className={classes.inputFields}
label={"Enter Phone Number "}
/>
<TextField
name="address"
value={input.address}
onChange={(e) => handleFormChange(index, e)}
className={classes.inputFields}
label={"Enter Address "}
/>
</div>
);
})}
<Button onClick={addUsers}>
<AddIcon /> Add More Users
</Button>

<Button type="submit" className={classes.inputFields}>
Submit
</Button>
</form>
</div>
);
}

export default CustomForm;

Create CustomForm.module.css in the same folder

.customform{
display: flex;
flex-direction: column;
margin:1%
}
.inputFields{
margin-top: 1% !important;

}
.heading{
text-align: center;
}
  • *we will create our api in the later part.

6. Create a Helper folder inside src. Inside Helper create a file named utils.js.

// utility function
export function getTenDigitRandomNumber(){
return Math.random().toString().substring(2, 12);
}

7. Setting up redux

Create a folder called Redux and create a file , name it Store.js

Store.js

import {configureStore, createSlice} from '@reduxjs/toolkit'
const INITIAL_STATE = { <- This object define the data structure for this application. Also it is the initial state of our app
totaluser:0,
users:[]
}
const userSlice = createSlice({ <- Creates a slice in redux-store
name:'userSlice',
initialState:INITIAL_STATE,
reducers:{
updateUserDetails(state,action){. <- reducers holds all the methods for a slice
if(action.payload!=null){
state.totaluser = action.payload.totaluser
state.users = action.payload.users
}
}
}
})

const store = configureStore({. < - Configuring the redux store
reducer:userSlice.reducer
})

export const userAction = userSlice.actions; <- Actions with which we will refer the methods
export default store

8. Create a new component under Components folder. Name it FinalPage.js

import React from 'react'
import DenseTable from './DenseTable'
import classes from './FinalPage.module.css'
function FinalPage() {
return (
<div className={classes.container}>
<h3>All Users</h3>
<DenseTable/>
</div>
)
}

export default FinalPage

Add css file for FinalPage and name it FinalPage.module.css

.container{
display: flex;
align-items: center;
flex-direction: column;
padding: 3%;
}

Create another file inside same folder and name it DenseTable.js

import { Paper, TableContainer,Table,TableHead,TableCell,TableRow,TableBody } from '@mui/material'
import React from 'react'
import {useSelector} from 'react-redux'

function DenseTable() {
const users = useSelector(state=>state.users)

return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<TableCell >Username</TableCell>
<TableCell align="right">Email</TableCell>
<TableCell align="right">address</TableCell>
<TableCell align="right">phone</TableCell>
</TableRow>
</TableHead>
<TableBody>
{users.map((row) => (
<TableRow
key={row.username}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell component="th" scope="row">
{row.username}
</TableCell>
<TableCell align="right">{row.email}</TableCell>
<TableCell align="right">{row.address}</TableCell>
<TableCell align="right">{row.phonenumber}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)
}

export default DenseTable

9. Wrap everything with the provider.

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from 'react-redux'
import store from './Redux/Store';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
</Provider>

);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Press enter or click to view image in full size
Press enter or click to view image in full size
Yes you can dynamically add as many forms as you want 🤠 our backend will handle everything

The Backend

For the backend, we will use Django and rest-framework.

  1. Create a brand new django app. Run “django-admin startproject backend” command in the terminal.
  2. Enter into the backend app and run “ python manage.py startapp myapis”
  3. Install corsheaders and rest_framework packages.

pip install django-cors-headers

pip install djangorestframework

4. Now inside the settings.py file add the “myapis”, ’corsheaders’ , ‘rest_framework’ app.

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapis',
'corsheaders',
'rest_framework',

]
# MiddleWare and cors settings inside settings.py

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',

]

CORS_ALLOWED_ORIGINS = [
'http://localhost:3000',
]
CSRF_TRUSTED_ORIGINS = [
'http://localhost:3000',
]

Entire settings.py

"""
Django settings for backend project.

Generated by 'django-admin startproject' using Django 4.0.3.

For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-hjt6w+@*1hsofny5uz@^-=4qv!i1+6r%=z3&7c$^vqta!+wx_n'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapis',
'corsheaders',
'rest_framework',

]

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',

]

CORS_ALLOWED_ORIGINS = [
'http://localhost:3000',
]
CSRF_TRUSTED_ORIGINS = [
'http://localhost:3000',
]

ROOT_URLCONF = 'backend.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

WSGI_APPLICATION = 'backend.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}


# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]


# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

5. Building the urls.

a. Inside the urls.py of “backend” add the following code

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('apis/v1/',include('myapis.urls'))
]

b. Add a urls.py file in myapis folder and add->

from django.urls import include, path
from .views import handleuserdata


urlpatterns = [
path('test/',handleuserdata)
]

6. Creating the models

Inside the models.py file add the following

from django.db import models

# Create your models here.
class Record(models.Model):
record_name = models.TextField(max_length=30)
def __str__(self):
return self.record_name

class UserModel(models.Model):
username = models.TextField(max_length=100,blank=True)
email = models.EmailField()
address = models.TextField(max_length=300)
phone = models.TextField(max_length=10)
createdDate = models.DateTimeField(auto_now_add=True,blank=True)
related_to = models.ForeignKey(Record,on_delete=models.CASCADE)

def __str__(self):
return self.username+' '+self.email

7. Adding models in admin panel

Inside the admin.py add

from django.contrib import admin

from myapis.models import UserModel,Record

# Register your models here.

admin.site.register(Record)

@admin.register(UserModel)
class UserModelAdmin(admin.ModelAdmin):
list_display = ('username', 'phone','related_to')
list_filter = ("related_to", )
search_fields = ("username__startswith", )

8. Run the following commands for making migrations in database.

“python manage.py makemigrations”

“python manage.py migrate”

Create a superuser with “python manage.py createsuperuser” command.

Press enter or click to view image in full size
You will get this kind of prompt

9. Inside views.py file of myapis add the following

from rest_framework.response import Response
from rest_framework import viewsets
from .serializers import UserModelSerializer,RecordModelSerializer
from .models import UserModel,Record
from rest_framework.decorators import api_view
import json
from django.http import JsonResponse
from rest_framework import status


@api_view(['POST'])
def handleuserdata(request):
data=''
count = 0
if(request.method=='POST'):
data = json.loads(request.body)
count = len(data['users'])
record = Record()
record.record_name = data['record_name']
record.save()
for user in data['users']:
username = user['username']
email = user['email']
phone = user['phonenumber']
address = user['address']
u = UserModel()
u.username = username
u.email=email
u.phone=phone
u.address=address
u.related_to = record
u.save()

data['totalnumberofusers'] = count
return JsonResponse({"data":data},safe=False,status=status.HTTP_200_OK)

10. Run the server with “python manage.py runserver”.

Go to this url -> “http://127.0.0.1:8000/apis/v1/test/

Press enter or click to view image in full size
Admin Panel

Visit the project in github

Leave a clap if you like the article. 😸