In this tutorial, we will learn how to build a full stack Django + React Hooks example with a CRUD App. The back-end server uses Django with Rest Framework for REST APIs and interacts with MySQL/PostgreSQL/MongoDB database. Front-end side is made with React, Hooks, Axios, React Router & Bootstrap.
Contents
- Django React Hooks example Overview
- Architecture of Django React example
- Django Rest Apis Back-end
- Overview
- Technology
- Project Structure
- Install Django REST framework
- Setup new Django project
- Setup Database engine
- Setup new Django app for Rest CRUD Api
- Configure CORS
- Define the Django Model
- Migrate Data Model to the database
- Create Serializer class for Data Model
- Define Routes to Views functions
- Write API Views
- Run the Django Rest Api Server
- React Hooks Front-end
- Further Reading
- Conclusion
Django React Hooks example Overview
We will build a full-stack Django & React Hooks Tutorial CRUD Application in that:
- Each Tutorial has id, title, description, published status.
- We can create, retrieve, update, delete Tutorials.
- We can also find Tutorials by title.
The images below shows screenshots of our System.
– Create an item:
– Retrieve all items:
– Click on Edit button to retrieve an item:
On this Page, you can:
- change status to Published using Publish button
- remove the Tutorial from Database using Delete button
- update the Tutorial details on Database with Update button
If you want to implement Form Validation, please visit:
React Form Validation with Hooks, Bootstrap | react-hook-form 7
– Search items by title:
Architecture of Django React example
This is the application architecture we’re gonna build:
– Django exports REST Apis using Django Rest Framework & interacts with Database using Django Model.
– React Client sends HTTP Requests and retrieve HTTP Responses using axios, shows data on the components. We also use React Router for navigating to pages.
Django Rest Apis Back-end
Overview
These are APIs that Django App will export:
Methods | Urls | Actions |
---|---|---|
POST | /api/tutorials | create new Tutorial |
GET | /api/tutorials | retrieve all Tutorials |
GET | /api/tutorials/:id | retrieve a Tutorial by :id |
PUT | /api/tutorials/:id | update a Tutorial by :id |
DELETE | /api/tutorials/:id | delete a Tutorial by :id |
DELETE | /api/tutorials | delete all Tutorials |
GET | /api/tutorials?title=[keyword] | find all Tutorials which title contains keyword |
Technology
- Django 2.1.15
- Django Rest Framework 3.11.0
- PyMySQL 0.9.3 (for MySQL)/ djongo 1.3.1 (for MongoDB)
- django-cors-headers 3.2.1
Project Structure
This is our Django project structure:
– tutorials/apps.py: declares TutorialsConfig
class (subclass of django.apps.AppConfig
) that represents Rest CRUD Apis app and its configuration.
– bzkRestApis/settings.py: contains settings for our Django project: Database engine, INSTALLED_APPS
list with Django REST framework, Tutorials Application, CORS and MIDDLEWARE
.
– tutorials/models.py: defines Tutorial data model class (subclass of django.db.models.Model
).
– migrations/0001_initial.py: is created when we make migrations for the data model, and will be used for generating database table.
– tutorials/serializers.py: manages serialization and deserialization with TutorialSerializer
class (subclass of rest_framework.serializers.ModelSerializer
).
– tutorials/views.py: contains functions to process HTTP requests and produce HTTP responses (using TutorialSerializer
).
– tutorials/urls.py: defines URL patterns along with request functions in the Views.
– bzkRestApis/urls.py: also has URL patterns that includes tutorials.urls
, it is the root URL configurations.
Install Django REST framework
Django REST framework helps us to build RESTful Web Services flexibly.
To install this package, run command:
pip install djangorestframework
Setup new Django project
Let’s create a new Django project with command:
django-admin startproject bzkRestApis
When the process is done, you can see folder tree like this:
Now we open settings.py and add Django REST framework to the INSTALLED_APPS
array here.
INSTALLED_APPS = [
...
# Django REST framework
'rest_framework',
]
Setup Database engine
Open settings.py and change declaration of DATABASES
:
DATABASES = {
'default': {
'ENGINE': ...,
'NAME': '...',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': ...,
}
}
For more details about specific parameters corresponding to a database, please visit one of the posts:
- Django CRUD with MySQL example | Django Rest Framework
- Django CRUD with PostgreSQL example | Django Rest Framework
- Django CRUD with MongoDB example | Django Rest Framework
Setup new Django app for Rest CRUD Api
Run following commands to create new Django app tutorials:
cd bzkRestApis
python manage.py startapp tutorials
Refresh the project directory tree, you can see it now looks like:
Now open tutorials/apps.py, you can see TutorialsConfig
class (subclass of django.apps.AppConfig
).
This represents the Django app that we’ve just created with its configuration:
from django.apps import AppConfig
class TutorialsConfig(AppConfig):
name = 'tutorials'
Don’t forget to add this app to INSTALLED_APPS
array in settings.py:
INSTALLED_APPS = [
...
# Tutorials application
'tutorials.apps.TutorialsConfig',
]
Configure CORS
We need to allow requests to our Django application from other origins.
In this example, we’re gonna configure CORS to accept requests from localhost:8081
.
First, install the django-cors-headers library:
pip install django-cors-headers
In settings.py, add configuration for CORS:
INSTALLED_APPS = [
...
# CORS
'corsheaders',
]
You also need to add a middleware class to listen in on responses:
MIDDLEWARE = [
...
# CORS
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]
Note: CorsMiddleware
should be placed as high as possible, especially before any middleware that can generate responses such as CommonMiddleware
.
Next, set CORS_ORIGIN_ALLOW_ALL and add the host to CORS_ORIGIN_WHITELIST:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'http://localhost:8081',
)
- CORS_ORIGIN_ALLOW_ALL: If
True
, all origins will be accepted (not use the whitelist below). Defaults toFalse
. - CORS_ORIGIN_WHITELIST: List of origins that are authorized to make cross-site HTTP requests. Defaults to
[]
.
Define the Django Model
Open tutorials/models.py, add Tutorial
class as subclass of django.db.models.Model
.
There are 3 fields: title, description, published.
from django.db import models
class Tutorial(models.Model):
title = models.CharField(max_length=70, blank=False, default='')
description = models.CharField(max_length=200,blank=False, default='')
published = models.BooleanField(default=False)
Each field is specified as a class attribute, and each attribute maps to a database column.
id field is added automatically.
Migrate Data Model to the database
Run the Python script: python manage.py makemigrations tutorials
.
The console will show:
Migrations for 'tutorials':
tutorials\migrations\0001_initial.py
- Create model Tutorial
Refresh the workspace, you can see new file tutorials/migrations/0001_initial.py.
It includes code to create Tutorial
data model:
# Generated by Django 2.1.15
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Tutorial',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(default='', max_length=70)),
('description', models.CharField(default='', max_length=200)),
('published', models.BooleanField(default=False)),
],
),
]
The generated code defines Migration
class (subclass of the django.db.migrations.Migration
).
It has operations array that contains operation for creating Customer model table: migrations.CreateModel()
.
The call to this will create a new model in the project history and a corresponding table in the database to match it.
To apply the generated migration above, run the following Python script:
python manage.py migrate tutorials
The console will show:
Operations to perform:
Apply all migrations: tutorials
Running migrations:
Applying tutorials.0001_initial... OK
At this time, you can see that a table/collection for Tutorial
model was generated automatically with the name: tutorials_tutorial in the database.
Create Serializer class for Data Model
Let’s create TutorialSerializer
class that will manage serialization and deserialization from JSON.
It inherit from rest_framework.serializers.ModelSerializer
superclass which automatically populates a set of fields
and default validators
. We need to specify the model class here.
tutorials/serializers.py
from rest_framework import serializers
from tutorials.models import Tutorial
class TutorialSerializer(serializers.ModelSerializer):
class Meta:
model = Tutorial
fields = ('id',
'title',
'description',
'published')
In the inner class Meta
, we declare 2 attributes:
model
: the model for Serializerfields
: a tuple of field names to be included in the serialization
Define Routes to Views functions
When a client sends request for an endpoint using HTTP request (GET, POST, PUT, DELETE), we need to determine how the server will response by defining the routes.
These are our routes:
/api/tutorials
: GET, POST, DELETE/api/tutorials/:id
: GET, PUT, DELETE/api/tutorials/published
: GET
Create a urls.py inside tutorials app with urlpatterns
containing url
s to be matched with request functions in the views.py:
from django.conf.urls import url
from tutorials import views
urlpatterns = [
url(r'^api/tutorials$', views.tutorial_list),
url(r'^api/tutorials/(?P<pk>[0-9]+)$', views.tutorial_detail),
url(r'^api/tutorials/published$', views.tutorial_list_published)
]
Don’t forget to include this URL patterns in root URL configurations.
Open bzkRestApis/urls.py and modify the content with the following code:
from django.conf.urls import url, include
urlpatterns = [
url(r'^', include('tutorials.urls')),
]
Write API Views
We’re gonna create these API functions for CRUD Operations:
– tutorial_list()
: GET list of tutorials, POST a new tutorial, DELETE all tutorials
– tutorial_detail()
: GET / PUT / DELETE tutorial by ‘id’
– tutorial_list_published()
: GET all published tutorials
Open tutorials/views.py and write following code:
from django.shortcuts import render
...
@api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(request):
# GET list of tutorials, POST a new tutorial, DELETE all tutorials
@api_view(['GET', 'PUT', 'DELETE'])
def tutorial_detail(request, pk):
# find tutorial by pk (id)
try:
tutorial = Tutorial.objects.get(pk=pk)
except Tutorial.DoesNotExist:
return JsonResponse({'message': 'The tutorial does not exist'}, status=status.HTTP_404_NOT_FOUND)
# GET / PUT / DELETE tutorial
@api_view(['GET'])
def tutorial_list_published(request):
# GET all published tutorials
You can continue with step by step to implement this Django Server in one of the posts:
- Django CRUD with MySQL example | Django Rest Framework
- Django CRUD with PostgreSQL example | Django Rest Framework
- Django CRUD with MongoDB example | Django Rest Framework
Run the Django Rest Api Server
Run our Django Project with command: python manage.py runserver 8080
.
The console shows:
Performing system checks...
System check identified no issues (0 silenced).
Django version 2.1.15, using settings 'bzkRestApis.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CTRL-BREAK.
React Hooks Front-end
Overview
Let’s see the React Application Diagram that we’re gonna implement:
– The App
component is a container with React Router
. It has navbar
that links to routes paths.
– TutorialsList
gets and displays Tutorials.
– Tutorial
has form for editing Tutorial’s details based on :id
.
– AddTutorial
has form for submission new Tutorial.
– They call TutorialDataService
functions which use axios
to make HTTP requests and receive responses.
Or you can use React with Redux:
More details at: React Redux CRUD App example with Rest API
Technology
- React 16
- react-router-dom 5.1.2
- axios 0.19.2
- bootstrap 4.4.1
Project Structure
Now look at the project directory structure:
– package.json contains 4 main modules: react
, react-router-dom
, axios
& bootstrap
.
– App
is the container that has Router
& navbar.
– There are 3 items using React hooks: TutorialsList
, Tutorial
, AddTutorial
.
– http-common.js initializes axios with HTTP base Url and headers.
– TutorialDataService
has functions for sending HTTP requests to the Apis.
– .env configures port for this React Hooks CRUD App.
Setup React.js Project
Open cmd at the folder you want to save Project folder, run command:
npx create-react-app react-hooks-crud
After the process is done. We create additional folders and files like the following tree:
public
src
components
AddTutorial.js
TUtorial.js
TutorialsList.js
services
TutorialService.js
App.css
App.js
index.js
package.json
Install Bootstrap for React Hooks CRUD App
Run command: npm install bootstrap
.
Open src/App.js and modify the code inside it as following-
import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
class App extends Component {
render() {
// ...
}
}
export default App;
Add React Router to React Hooks CRUD App
– Run the command: npm install react-router-dom
.
– Open src/index.js and wrap App
component by BrowserRouter
object.
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
serviceWorker.unregister();
Open src/App.js, this App
component is the root container for our application, it will contain a navbar
, and also, a Switch
object with several Route
. Each Route
points to a React Component.
import React from "react";
import { Switch, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import AddTutorial from "./components/AddTutorial";
import Tutorial from "./components/Tutorial";
import TutorialsList from "./components/TutorialsList";
function App() {
return (
<div>
<nav className="navbar navbar-expand navbar-dark bg-dark">
<a href="/tutorials" className="navbar-brand">
bezKoder
</a>
<div className="navbar-nav mr-auto">
<li className="nav-item">
<Link to={"/tutorials"} className="nav-link">
Tutorials
</Link>
</li>
<li className="nav-item">
<Link to={"/add"} className="nav-link">
Add
</Link>
</li>
</div>
</nav>
<div className="container mt-3">
<Switch>
<Route exact path={["/", "/tutorials"]} component={TutorialsList} />
<Route exact path="/add" component={AddTutorial} />
<Route path="/tutorials/:id" component={Tutorial} />
</Switch>
</div>
</div>
);
}
export default App;
Initialize Axios for React CRUD HTTP Client
Let’s install axios with command: npm install axios
.
Under src folder, we create http-common.js file with following code:
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-type": "application/json"
}
});
You can change the baseURL
that depends on REST APIs url that your Server configures.
Create Data Service
In this step, we’re gonna create a service that uses axios object above to send HTTP requests.
The service exports CRUD functions and finder method:
- CREATE:
create
- RETRIEVE:
getAll
,get
- UPDATE:
update
- DELETE:
remove
,removeAll
- FINDER:
findByTitle
services/TutorialService.js
import http from "../http-common";
const getAll = () => {
return http.get("/tutorials");
};
const get = id => {
return http.get(`/tutorials/${id}`);
};
const create = data => {
return http.post("/tutorials", data);
};
const update = (id, data) => {
return http.put(`/tutorials/${id}`, data);
};
const remove = id => {
return http.delete(`/tutorials/${id}`);
};
const removeAll = () => {
return http.delete(`/tutorials`);
};
const findByTitle = title => {
return http.get(`/tutorials?title=${title}`);
};
export default {
getAll,
get,
create,
update,
remove,
removeAll,
findByTitle
};
We call axios (imported as http) get
, post
, put
, delete
method corresponding to HTTP Requests: GET, POST, PUT, DELETE to make CRUD Operations.
Create React Page Components
Now we’re gonna build 3 components corresponding to 3 Routes defined before:
- Add Tutorial
- Tutorial Details
- List of Tutorials
You can continue with step by step to implement this React App in the post:
– React.js CRUD example to consume Web API
– or React Hooks CRUD example to consume Web API
Using React with Redux:
– React Redux CRUD example with Rest API
– React Hooks + Redux: CRUD example with Rest API
Run React Hooks CRUD App
You can run our App with command: npm start
.
If the process is successful, open Browser with Url: http://localhost:8081/
and check it.
Further Reading
Serverless with Firebase:
– React Hooks + Firebase Realtime Database: CRUD App
– React Hooks + Firestore example: CRUD app
Conclusion
Now we have an overview of Django React Hooks example when building a CRUD App that interacts with database. We also take a look at client-server architecture for REST API using Django Rest Framework, as well as React Hooks & Axios project structure for building a front-end app to make HTTP requests and consume responses.
Next tutorials show you more details about how to implement the system (including source code):
– Back-end:
– Front-end:
Happy learning, see you again!
very2 good tutorial, can’t find like this anywhere on net. thanks.
can you give me this in github
Hi, you can find github source code inside tutorials that I gave in Conclusion section.
I cant find the link to github 🙁
Here you are.
– React Client: https://github.com/bezkoder/react-hooks-crud-web-api
– Django Server: https://github.com/bezkoder/django-rest-api
Thanks for your tutorial and great explanation , keep going
Thanks so much for the tutorial. I literally have an interview due on Friday and this is what I need to show as a full stack software developer intern. Crud Operations and log in. I am headed to the authentication tutorial with react-redux right now. Thanks a lot
Is there any chance you have plans to make a tutorial that combines Django, React w/ Hooks, and JWT Authentication?
Hi, I will write the tutorial when having time 🙂 Thanks for your suggestion 🙂