How to create a CRUD application in ReactJS and Django Rest Framework
Tags: django, react, api
Published: 2023-10-04 12:26:01

In this post, I am creating a simple CRUD application with the help of ReactJs and Django Rest Framework. We will divide this post into two parts - `Frontend` and `Backend`.

In the frontend part, we will use ReactJS for client-side handling and API calls. Conversely, the Backend part will use the Django rest framework for making APIs.

Before starting the tutorial we have to install some packages/libraries in Frontend and Backend.
For Frontend, we need to install-
* axios - for API calls
* react-router-dom - for routing between the pages

For Backend, we need to install-
* [djangorestframework](pip install djangorestframework)
* [django-cors-headers](https://pypi.org/project/django-cors-headers/)

---

## Frontend
### _App.js_
```javascript
import './App.css';
import { createBrowserRouter, createRoutesFromElements, Route, RouterProvider } from 'react-router-dom';
import Home from './Components/Home';
import About from './Components/About';
import Contact from './Components/Contact';
import Edit from './Components/Edit';
import Root from './Components/Root';

function App() {
  const url = "http://127.0.0.1:8000/"

  const router = createBrowserRouter(createRoutesFromElements(
    <Route path="/" element={<Root/>}>
      <Route index element={<Home url={url}/>}/>
      <Route path="/about"  element={<About/>}/>
      <Route path="/contact"  element={<Contact/>}/>
      <Route path="/edit/:id/"  element={<Edit url={url}/>}/>
    </Route>
  ))
  
  return (
    <div>
        <RouterProvider router={router}/>       
    </div>
  );
}

export default App;
```
### Components/Root.js
```javascript
import { Link, Outlet } from "react-router-dom";
function Root(){
    return(
        <>
            <nav className="navbar navbar-expand-lg bg-body-tertiary" data-bs-theme="dark">
                <div className="container-fluid">
                    <a className="navbar-brand" href="#">React+DRF</a>
                    <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                        <span className="navbar-toggler-icon"></span>
                    </button>
                    <div className="collapse navbar-collapse" id="navbarSupportedContent">
                        <ul className="navbar-nav me-auto mb-2 mb-lg-0">
                            <li className="nav-item">
                                <Link to='/' className="nav-link active" aria-current="page" href="#">Home</Link>
                            </li>
                            <li className="nav-item">
                                <Link to='/about' className="nav-link active" href="#">About</Link>
                            </li>
                            <li className="nav-item">
                                <Link to='/contact' className="nav-link active" href="#">Contact</Link>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        

        <div>
            <Outlet/>
        </div>
        </>
    )
}
export default Root;
```

### Components/Home.js
```js
import axios from "axios";
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";

function Home(props){
    useEffect(()=>{
        getData();
    },[])
    
    const [users, setUsers] = useState([]);
    const [username, setUsername] = useState();
    const [password, setPassword] = useState();

    // Fetching the data from DRF API
    async function getData(){
        const response = await axios.get(props.url);
        setUsers(response.data);
    }

    // Posting the data to DRF API
    async function handleSubmit(e){
        e.preventDefault();
        let data = {
            user_name: username,
            password: password
        }
        await axios.post(props.url+'create_user/', data, {
            headers:{
                'Content-Type': 'multipart/form-data'
            }
        });
        getData();
    }

    //Delete a specific user
    const deleteUser=(user_id)=>{
      axios.delete(props.url+`delete_user/${user_id}/`, {id:user_id})
      .then(()=>getData())
      .catch((err)=>console.log(err))

    }
    return(
        
        <div className="container w-50 my-5">
            <form onSubmit={handleSubmit}>
            <div className="mb-3">
                <label htmlFor="exampleFormControlInput1" className="form-label">Username</label>
                <input type="text" className="form-control" id="exampleFormControlInput1" value={username} onChange={(e)=>setUsername(e.target.value)} placeholder="Username"/>
            </div>

            <div className="mb-3">
                <label htmlFor="exampleFormControlInput2" className="form-label">Password</label>
                <input type="password" className="form-control" id="exampleFormControlInput2" value={password} onChange={(e)=>setPassword(e.target.value)} placeholder="Password"/>
            </div>
            <input type="submit" className="btn btn-primary form-control" value="ADD"/>
            </form>
        
            <br/>
            <table className="table text-center" border={1} cellPadding={5}>
                <tbody>
                <tr>
                    <th>Id</th>
                    <th>Username</th>
                    <th>Password</th>
                    <th>Operation</th>
                </tr>

                {
                    users.map((user=>{
                        return(
                            <tr key={user.id}>
                                <td>{user.id}</td>
                                <td>{user.user_name}</td>
                                <td>{user.password}</td>
                                <td>
                                    <Link className="btn btn-sm btn-primary mx-3" to={`/edit/${user.id}`} state={{uname: user.user_name, pwd: user.password}}>Edit</Link>
                                    <button className="btn btn-sm btn-danger" onClick={()=>deleteUser(user.id)}>Delete</button>
                                </td>
                            </tr>
                        )
                    }))
                }
                </tbody>
            </table>
            </div>
    )
}
export default Home;
```

### Components/Edit.js
```javascript
import axios from "axios";
import { useState } from "react";
import { useLocation, useParams, useNavigate } from "react-router-dom";
function Edit(props) {
    const location = useLocation();
    const userId = useParams()
    const [username, setUsername] = useState(location.state.uname);
    const [password, setPassword] = useState(location.state.pwd);
    const navigate = useNavigate();
    
    const updateUser = async (e) =>{
        e.preventDefault()
        const response = await axios.put(props.url+`update_user/${userId.id}/`, {user_name: username, password: password});
        navigate("/")
    }
    

    return(
        <div className="container w-50 my-5">
            <form onSubmit={updateUser}>
                <div className="mb-3">
                    <label for="exampleFormControlInput1" className="form-label">Username</label>
                    <input type="text" className="form-control" id="exampleFormControlInput1" value={username} onChange={(e)=>setUsername(e.target.value)} placeholder="Username"/>
                </div>

                <div className="mb-3">
                    <label for="exampleFormControlInput2" className="form-label">Password</label>
                    <input type="password" className="form-control" id="exampleFormControlInput2" value={password} onChange={(e)=>setPassword(e.target.value)} placeholder="Password"/>
                </div>
                <input type="submit" className="btn btn-primary form-control" value="Update"/>
            </form>
        </div>
    )
}

export default Edit;
```

### Components/About.js
```js
function About(){
    return(
        <h1>About page</h1>
    )
}
export default About;
```

### Components/Contact.js
```js
function Contact(){
    return(
        <h1>Contact page</h1>
    )
}
export default Contact;
```

---
## Backend
### settings.py
We have to create a `main` app in our project and add `main`, `rest_framework` and `corsheaders` in INSTALLED_APPS and also add some MIDDLEWARE in settings.py.
```python
INSTALLED_APPS = [
    .
    .
    'main',
    'rest_framework',
    'corsheaders'
]
CORS_ALLOW_ALL_ORIGINS=True


MIDDLEWARE = [
    .
    .
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',    
]
```

### project's urls.py
```python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('main.urls')),
]

```

### models.py
Create a `MyUser` model that contains `user_name` and `password`.
```python
from django.db import models

class MyUser(models.Model):
    user_name = models.CharField(max_length=50)
    password = models.CharField(max_length=50)

    def __str__(self):
        return self.user_name
    
```

### admin.py
Register above model in admin.py file like this-
```python
from django.contrib import admin
from .models import MyUser
admin.site.register(MyUser)
```

### serializers.py
```python
from rest_framework import serializers
from .models import MyUser

class MyUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyUser
        fields = "__all__"

```

### views.py
```python
from .models import MyUser
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import MyUserSerializer

@api_view(['GET'])
def getData(request):
    users = MyUser.objects.all()
    users_serializer = MyUserSerializer(users, many=True)
    return Response(users_serializer.data)


@api_view(['POST'])    
def create_user(request):
    if request.method=='POST':
        data=request.data
        serializer = MyUserSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response("Errrro")
    

@api_view(['PUT'])    
def update_user(request, id):
    if request.method=='PUT':
        data=request.data
        user_obj = MyUser.objects.get(id=id)
        serializer = MyUserSerializer(user_obj, data=data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response("Errrro")
    
@api_view(['DELETE'])    
def delete_user(request, id):
    if request.method=='DELETE':
        data=request.data
        user_obj = MyUser.objects.get(id=id)
        user_obj.delete()
        return Response("Delete succesffully")
```

### urls.py
```python
from django.urls import path
from . import views

urlpatterns  = [
    path('', views.getData),
    path('create_user/', views.create_user),
    path('update_user/<int:id>/', views.update_user),
    path('delete_user/<int:id>/', views.delete_user),
]
```

To run react server you have to open `frontend` directory in cmd and run this command - `npm start`
To run backend server you have to open `backend` directory in cmd and run this command - `python manage.py runserver`

Code is also available on [Github](https://github.com/MadhubanKhatri/django_react_api)