Django is a Python backend web framework that is used to build secure and scalable website applications whereas React is a front-end Javascript framework that uses components in creating user interfaces for single-page applications.
We will be creating an application that consumes React for the user interface and Django for the API of our application using the Django REST framework (DRF).
Prerequisites
Following are the prerequisites needed to start with the project:
- Python
- Node.js
- VS Code ( or, IDE of your choice)
Use the following command in your command prompt to verify if you have python installed.
python -V
It will show you the current python version in your system.
Use the below command to check if the Node module is installed
node –version
It will show you the node version installed in your system.
It is good to go now as we have python and Node js installed in our system.
We will be starting with the backend.
Implementing: Django(Backend)
Open your Command prompt and follow the given below steps:
Step 1: Using the below mention command create a directory named “Django-react-app”
mkdir django-react-app
Step 2: Create the below command by moving into the directory
cd Django-react-project
Step 3: Using the below mention command create a virtual environment
python -m venv dar
Step 4: Below given command can be used to activate the virtual environment
dar\Scripts\activate.bat
Step 5: Using the below mentioned install Django inside the virtual machine.
pip install Django
Step 6: Create a project for the Django backend by giving a name to the project. Use the command mentioned below:
django-admin startproject “projectname”
There will be one folder of the Django-react app which will be the main folder and two subfolders: one for the backend and one for the front end which will be created later.
Step 7: Navigate to the backend folder using the below command:
cd backend
Step 8: Using the following command Start the app and call it “todo”
python manage.py startapp todo
Step 9: To Migrate the project use the below command:
python manage.py migrate
Step 10: Run the server using the below command:
python manage.py runserver
Visit the local host to verify if the project has started properly. As you can see below image the project is up and running:
Step 11: Here take some configuration steps inside the file settings.py.
Add the name of the app “todo” in the INSTALLED_APPS section as shown below:
# Application definition
INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘todo’,
The settings.py file at this point would look like the below:
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/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ‘django-insecure-_c3!4)8+yce2l-ju@gz@b6(e0$00y@xhx7+lxk1p==k+pyqko3’
# 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’,
‘todo’,
]
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’,
]
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/3.2/ref/settings/#databases
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.sqlite3’,
‘NAME’: BASE_DIR / ‘db.sqlite3’,
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/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/3.2/topics/i18n/
LANGUAGE_CODE = ‘en-us’
TIME_ZONE = ‘UTC’
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = ‘/static/’
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = ‘django.db.models.BigAutoField’
Step 12: Create a Model. The model will explain how the to-do items are stored in the database. There will be three properties in the model:
Title: Title of the task with 150 characters maximum length.
Description: Description of the task with 500 characters maximum length.
Completed: A Boolean value that is used to determine the status of the task. It will be set to false by default.
So go ahead and open the models.py file and the following code:
class Todo(models.Model):
title=models.CharField(max_length=150)
description=models.CharField(max_length=500)
completed=models.BooleanField(default=False)
Create a string representation of the title inside the Todo class as follows:
def __str__(self):
#it will return the title
return self.title G”)
Our models.py file will look like this at this point:
from Django.db import models
class Todo(models.Model):
title=models.CharField(max_length=150)
description=models.CharField(max_length=500)
completed=models.BooleanField(default=False)
# string representation of the class
def __str__(self):
#it will return the title
return self.title
Step 13: Now make migrations.
Note: every time you make changes to the models.py file, you need to make migrations. Make the migrations using the below command:
python manage.py makemigrations
A message will be generated when your migration is ready
Step 14: Using the below command, apply all migrations using the below command:
python manage.py migrate
This will apply your migrations
Do a test to see if CRUD operations work on the model file by using the admin site. Register the model in the admin.py file.
Step 15: Open the admin.py file and add the below mentioned code in it:
from Django.contrib import admin
# import the model Todo
from .models import Todo
# create a class for the admin-model integration
class TodoAdmin(admin.ModelAdmin):
# add the fields of the model here
list_display = (“title”,”description”,”completed”)
# we will need to register the
# model class and the Admin model class
# using the register() method
# of admin.site class
admin.site.register(Todo,TodoAdmin)
Step 16: Create a superuser by using below mention command:
python manage.py createsuperuser
Fill up the credentials
Username:
Email address:
Password:
Set up the credentials as per your need
You would receive a message when the superuser gets created:
Step 17: Run the server and check if everything is working properly by using the following command:
python manage.py runserver
The next step is to navigate the following link:
http://127.0.0.1:8000/admin/login/?next=/admin/
You will see an admin page
Fill up your credentials and log in. Use the credentials you have made while creating the superuser:
It will lead to the following page. You can see users, the app, and the groups as shown below:
Users:
Todo:
Now add some tasks to it and save it.
API Creation:
You need to install the Django REST framework. You also have Django-cors-headers for port 300 whitelisting as it is a default port for React.
Below are the steps to create the Django REST framework:
Step 1: Use the below mention command to install the Django REST framework in the backend directory:
pip install djangorestframework
once the installation is completed a message will displayed:
Step 2: Now using below command install the Django-cors-headers using the below command:
pip install django-cors-headers
You will receive a message.
Step 3: Open the setting.py file and add both the dependencies that you have just installed to INSTALLED_APPS:
INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘todo’,
‘corsheaders’,
‘rest_framework’,
]
Step 4: Whitelist the localhost port 3000 in the settings.py file.
Note: If you don’t whitelist, there will be a block between the localhost:8000 and localhost:3000.
Now add the following code:
# White listing the localhost:3000 port
# for React
CORS_ORIGIN_WHITELIST = (
‘http://localhost:3000’,
)
Step 5: You need to add the cors-header in the MIDDLEWARE section:
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’
]
Your settings.py will look like the below:
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/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ‘django-insecure-_c3!4)8+yce2l-ju@gz@b6(e0$00y@xhx7+lxk1p==k+pyqko3’
# 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’,
‘todo’,
‘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’
]
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/3.2/ref/settings/#databases
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.sqlite3’,
‘NAME’: BASE_DIR / ‘db.sqlite3’,
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/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’,
},
]
# White listing the localhost:3000 port
CORS_ORIGIN_WHITELIST = (
‘http://localhost:3000’
)
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = ‘en-us’
TIME_ZONE = ‘UTC’
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = ‘/static/’
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = ‘django.db.models.BigAutoField’
Create Serializers for the data model. It is responsible for converting model instances to JSON. It will easily help the front end to work with the received data easily.
JSON is the standard for data interchange on the web.
Step 6: Create a file inside the todo folder and name it as Add the below code inside the folder.
# import serializers from the REST framework
from rest_framework import serializers
# import the todo data model
from .models import Todo
# create a serializer class
class TodoSerializer(serializers.ModelSerializer):
# create a meta class
class Meta:
model = Todo
fields = (‘id’, ‘title’,’description’,’completed’)
Step 7: Creating Views. Open up the views.py file. Add the below code to the file:
from django.shortcuts import render
# import view sets from the REST framework
from rest_framework import viewsets
# import the TodoSerializer from the serializer file
from .serializers import TodoSerializer
# import the Todo model from the models file
from .models import Todo
# create a class for the Todo model viewsets
class TodoView(viewsets.ModelViewSet):
# create a serializer class and
# assign it to the TodoSerializer class
serializer_class = TodoSerializer
# define a variable and populate it
# with the Todo list objects
queryset = Todo.objects.all()
Step 8: Open the urls.py file and add the below code to it.
from django.contrib import admin
# add include to the path
from django.urls import path, include
# import views from todo
from todo import views
# import routers from the REST framework
# it is necessary for routing
from rest_framework import routers
# create a router object
router = routers.DefaultRouter()
# register the router
router.register(r’tasks’,views.TodoView, ‘task’)
urlpatterns = [
path(‘admin/’, admin.site.urls),
# add another path to the url patterns
# when you visit the localhost:8000/api
# you should be routed to the django Rest framework
path(‘api/’, include(router.urls))
]
This will be the final step for creating the REST API and now you can now perform all CRUD operations. Routers allow us to make queries.
At this step you need to check if you are moving forward in the right direction. Run the server and navigate to the following URL:
localhost:8000/api
You will get the below outcome:
You can see the API is up and running.
If you navigate to the following links, you can view and interact with your tasks:
locaLHOST:8000/api/tasks
Frontend(React js):
Building the frontend for the app. Follow the below mentioned steps.
Step 1: Activate the virtual environment to Navigate the main project directory(ie, Django-react-app) using the below command:
dar\Scripts\activate.bat
Step 2: Use the below command to create a boilerplate of React js app:
npx create-react-app frontend
Step 3: To install reactstrap and bootstrap in the project use the below command:
npm install reactstrap bootstrap
Step 4: First move into the Frontend folder and use the below command to run the React server to make sure everything if working till this point:
npm start
Step 5: Open the App.js file in the frontend folder. Clear the boilerplate code and change it to the below code:
import “./App.css”;
function App() {
return <div className=”App”><h2>Welcome to Geeksforgeeks!</h2></div>;
}
export default App;
Step 6: Now the code to the App.js file. Comments are added to the code for better understanding.
// import Component from the react module
import React, { Component } from “react”;
import Modal from “./components/Modal”;
import axios from ‘axios’;
// create a class that extends the component
class App extends Component {
// add a constructor to take props
constructor(props) {
super(props);
// add the props here
this.state = {
// the viewCompleted prop represents the status
// of the task. Set it to false by default
viewCompleted: false,
activeItem: {
title: “”,
description: “”,
completed: false
},
// this list stores all the completed tasks
taskList: []
};
}
// Add componentDidMount()
componentDidMount() {
this.refreshList();
}
refreshList = () => {
axios //Axios to send and receive HTTP requests
.get(“http://localhost:8000/api/tasks/”)
.then(res => this.setState({ taskList: res.data }))
.catch(err => console.log(err));
};
// this arrow function takes status as a parameter
// and changes the status of viewCompleted to true
// if the status is true, else changes it to false
displayCompleted = status => {
if (status) {
return this.setState({ viewCompleted: true });
}
return this.setState({ viewCompleted: false });
};
// this array function renders two spans that help control
// the set of items to be displayed(ie, completed or incomplete)
renderTabList = () => {
return (
<div className=”my-5 tab-list”>
<span
onClick={() => this.displayCompleted(true)}
className={this.state.viewCompleted ? “active” : “”}
>
completed
</span>
<span
onClick={() => this.displayCompleted(false)}
className={this.state.viewCompleted ? “” : “active”}
>
Incompleted
</span>
</div>
);
};
// Main variable to render items on the screen
renderItems = () => {
const { viewCompleted } = this.state;
const newItems = this.state.taskList.filter(
(item) => item.completed === viewCompleted
);
return newItems.map((item) => (
<li
key={item.id}
className=”list-group-item d-flex justify-content-between align-items-center”
>
<span
className={`todo-title mr-2 ${
this.state.viewCompleted ? “completed-todo” : “”
}`}
title={item.description}
>
{item.title}
</span>
<span>
<button
onClick={() => this.editItem(item)}
className=”btn btn-secondary mr-2″
>
Edit
</button>
<button
onClick={() => this.handleDelete(item)}
className=”btn btn-danger”
>
Delete
</button>
</span>
</li>
));
};
toggle = () => {
//add this after modal creation
this.setState({ modal: !this.state.modal });
};
handleSubmit = (item) => {
this.toggle();
alert(“save” + JSON.stringify(item));
};
// Submit an item
handleSubmit = (item) => {
this.toggle();
if (item.id) {
// if old post to edit and submit
axios
.put(`http://localhost:8000/api/tasks/${item.id}/`, item)
.then((res) => this.refreshList());
return;
}
// if new post to submit
axios
.post(“http://localhost:8000/api/tasks/”, item)
.then((res) => this.refreshList());
};
// Delete item
handleDelete = (item) => {
axios
.delete(`http://localhost:8000/api/tasks/${item.id}/`)
.then((res) => this.refreshList());
};
handleDelete = (item) => {
alert(“delete” + JSON.stringify(item));
};
// Create item
createItem = () => {
const item = { title: “”, description: “”, completed: false };
this.setState({ activeItem: item, modal: !this.state.modal });
};
//Edit item
editItem = (item) => {
this.setState({ activeItem: item, modal: !this.state.modal });
};
// Start by visual effects to viewer
render() {
return (
<main className=”content”>
<h1 className=”text-success text-uppercase text-center my-4″>
GFG Task Manager
</h1>
<div className=”row “>
<div className=”col-md-6 col-sm-10 mx-auto p-0″>
<div className=”card p-3″>
<div className=””>
<button onClick={this.createItem} className=”btn btn-info”>
Add task
</button>
</div>
{this.renderTabList()}
<ul className=”list-group list-group-flush”>
{this.renderItems()}
</ul>
</div>
</div>
</div>
{this.state.modal ? (
<Modal
activeItem={this.state.activeItem}
toggle={this.toggle}
onSave={this.handleSubmit}
/>
) : null}
</main>
);
}
}
export default App;
Step 7: Clear the CSS inside the Index.css file and add the below CSS:
.todo-title {
cursor: pointer;
}
.completed-todo {
text-decoration: line-through;
}
.tab-list > span {
padding: 5px 8px;
border: 1px solid rgb(7, 167, 68);
border-radius: 10px;
margin-right: 5px;
cursor: pointer;
}
.tab-list > span.active {
background-color: rgb(6, 139, 12);
color: #fff;
}
Step 8: Now create a new folder named “Components” in the src directory and add a file Modal.js to it. Then add the following code to it.
import React, { Component } from “react”;
// importing all of these classes from reactstrap module
import {
Button,
Modal,
ModalHeader,
ModalBody,
ModalFooter,
Form,
FormGroup,
Input,
Label
} from “reactstrap”;
// build a class base component
class CustomModal extends Component {
constructor(props) {
super(props);
this.state = {
activeItem: this.props.activeItem
};
}
// changes handler to check if a checkbox is checked or not
handleChange = e => {
let { name, value } = e.target;
if (e.target.type === “checkbox”) {
value = e.target.checked;
}
const activeItem = { …this.state.activeItem, [name]: value };
this.setState({ activeItem });
};
// rendering modal in the custommodal class received toggle and on save as props,
render() {
const { toggle, onSave } = this.props;
return (
<Modal isOpen={true} toggle={toggle}>
<ModalHeader toggle={toggle}> Task Item </ModalHeader>
<ModalBody>
<Form>
{/* 3 formgroups
1 title label */}
<FormGroup>
<Label for=”title”>Title</Label>
<Input
type=”text”
name=”title”
value={this.state.activeItem.title}
onChange={this.handleChange}
placeholder=”Enter Task Title”
/>
</FormGroup>
{/* 2 description label */}
<FormGroup>
<Label for=”description”>Description</Label>
<Input
type=”text”
name=”description”
value={this.state.activeItem.description}
onChange={this.handleChange}
placeholder=”Enter Task Description”
/>
</FormGroup>
{/* 3 completed label */}
<FormGroup check>
<Label for=”completed”>
<Input
type=”checkbox”
name=”completed”
checked={this.state.activeItem.completed}
onChange={this.handleChange}
/>
Completed
</Label>
</FormGroup>
</Form>
</ModalBody>
{/* create a modal footer */}
<ModalFooter>
<Button color=”success” onClick={() => onSave(this.state.activeItem)}>
Save
</Button>
</ModalFooter>
</Modal>
);
}
}
export default CustomModal
Step 9: Make the changes to the index.js file as follows:
import React from “react”;
import ReactDOM from “react-dom”;
import “./index.css”;
import App from “./App”;
// importing css stylesheet to use the bootstrap class
// add this line only in this file
import “bootstrap/dist/css/bootstrap.min.css”;
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById(“root”)
);
API Connection:
We will need to install Axios to make requests to the API endpoints on the Django backend server. To install Axios, use the below command inside the frontend folder:
npm install axios
Congratulations! You have successfully built a Fullstack Django-React app and used the Django REST framework to establish communication between the frontend and backend!
Add comment