Connect a React app into Django website's API

Clock
24.07.2024
Clock
15.04.2025
Clock
14 minutes
An eye
70
Hearts
0
Connected dots
0
Connected dots
0
Connected dots
0

Introduction

In this article, I will describe a process of integrating the React framework into the Django website. We will configure a communication API between both of them. Also, a TailwindCSS library will be connected for further simplification of website building.
All source code can be found on github. The name of the branch is simple-integration-react-django https://github.com/DmRafaule/SearchResultParser/tree/simple-integration-react-django

Creation of a basic django project

The root directory of a project will be called SearchResultParser. And inside of it, you need to create your django project with the same name, SearchResultParser. After installing a basic project, we may continue to create the first app for this project.

Creation of a basic django app

Before you jump by hyperlink in chapter name to other article, you must know, my app is going to be called Main, and it will have django model called Result; for the admin page model, it will be called ResultAdmin; and you will have to add the next fields:
  • user (CharField)
  • file (FileField)
  • time_created (DateTimeField)

Setting up an API for communication between React and Django

Installing API


pip install djangorestframework django-cors-headers
In a file settings.py, there is a need to add the next apps, coreheaders, and rest_framework into INSTALLED_APP. Also, you need to add one middleware, corsheaders.middleware.CorsMiddleware into MIDDLEWARE list.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'rest_framework',
    'Main.apps.MainConfig',
]

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',
]
Now, add next lines into settings.py

CORS_ORIGIN_WHITELIST = [
    'http://localhost:3000'
]

Creating a serializer for a model

For the frontend part of the website to work with django models, we must get them in some ways. For that reason, we will create a serializer(exporter) which is going to convert django models into json file responses.
Create a new file in Main directory.

cd Main
touch serializers.py
Paste it into that file:

from rest_framework import serializers
from .models import Result

class ResultSerializer(serializers.ModelSerializer):
    class Meta:
        model = Result
        fields = (‘id’, 'user', 'file', 'time_created')

Preparing and setting up APIs

In a file Main/views.py, let’s add a new view for API calls. A file will have next content:

from django.shortcuts import render
from rest_framework import viewsets
from .serializers import ResultSerializer
from .models import Result

class ResultView(viewsets.ModelViewSet):
    serializer_class = ResultSerializer
    queryset = Result.objects.all()

def home(request):
    return render(request, 'Main/home.html')
In a file SearchResultParser/urls.py, we must create a router and add new paths. New content of the file:

from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from Main import views

router = routers.DefaultRouter()
router.register(r'results', views.ResultView, 'result')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
    path('', include('Main.urls'))
]
After all of those manipulations, you will have the next working URLs patterns:
  • localhost:8000/api/results – Here you can see all records in your database.
  • localhost:8000/api/results/1/ - Here you can see data in a specified record by typing an ID

Creating base project in React

I’ve created a react project in the root directory, where you have .venv folder, and call it searchresultparser-frontend.

Installing and setting up a TailwindCSS library in a project (optional)

It is optional. If you think you have a better library to use and manage CSS, go for it. Entering a react project folder:

cd  searchresultparser-frontend
Install the new package:

npm install -D tailwindcss
Create a configuration file (tailwind.config.js) and a little bit change it.

npx tailwindcss init
Replace the inner content of searchresultparser-frontend/tailwind.config.js by:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
	"./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Now add a basic directives in a searchresultparser-frontend/src/index.css file

@tailwind base;
@tailwind components;
@tailwind utilities; 
Build and run:

npm run start
Now the Tailwindcss library is ready for use.

Creating a basic interface on React

Modal window

In a directory searchresultparser-frontend/src/, create a new file:

touch Modal.js
This file is describing how a modal window will appear and what it will looks like. This UI element is going to be helpful in the future in the case of sending requests via forms and the API of our website. Paste the next content in a Modal.js file:


import React from "react";
 
const Modal = ({ isOpen, onClose, children }) => {
    if (!isOpen) return null;

    return (
        <div className="fixed top-0 left-0 w-full h-full bg-opacity-50 flex items-center justify-center">
            <div className="bg-white h-auto  min-w-80  p-3 rounded border-2 z-10 gap-3">
                {children}
                <div className="flex justify-end  mr-2">
                    <div onClick={onClose} className="bg-red-400 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Close</div>
                </div>
            </div>
        </div>
    );
};
 
export default Modal;

Webpage of the app

The next ‘piece’ of code describing a basic interface for communication with a server and execution of such basic operations as CRUD. Open an App.js file and replace it with this:


import React, { useState } from 'react';
import Modal from './Modal';

var items =[
  {
    id: 1,
    user: "dima",
    file: "0020kfjewl01232",
    time_created: "11.07.24"
  },
  {
    id: 2,
    user: "artur",
    file: "ert0k355wl01232",
    time_created: "12.07.24"
  },
  {
    id: 3,
    user: "pasha",
    file: "aaaakfje23ddf32",
    time_created: "13.07.24"
  },
];

let currentChildren = null

function App() {
  const [isModal, setOpen] = React.useState(false);
  const renderItems = () => {
    return items.map((item) => (
        <div className="flex flex-row pl-4 h-8 border-2 rounded bg-amber-100">
        <div className="flex-grow">
          {item.user+'__'+item.file}
        </div>
        <div className="flex">
          <div onClick={()=> editItem(item)} className="bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Edit</div>
          <div onClick={()=> deleteItem(item)} className="bg-orange-300 pl-3 pr-3 hover:bg-orange-50 active:scale-150 hover:cursor-pointer transition-transform">Delete</div>
        </div>
      </div>
    ));
  }
  const handleClose = () => {
    setOpen(false);
  };
 
  const handleOpen = () => {
    setOpen(true);
  };

  const deleteItem = (item) => {
    handleOpen();
    currentChildren = 
    <div className='flex flex-col justify-between h-full gap-9'>
      <b className='flex w-full justify-center text-lg'>
        DELETE ITEM
      </b>  
      <div className='flex w-full justify-center'>
        Are you sure ?
      </div>
      <div className='flex w-full justify-center gap-2'>
        <button className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>Yes</button>
        <button className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>No</button>
      </div>
    </div>
  };
  
  const createItem = () => {
    handleOpen();
    currentChildren = 
      <div>
        <b className='flex w-full justify-center text-lg'>
          ADD NEW ITEM
        </b>  
        <div className='flex w-full justify-around g-4'>
          <form className='flex flex-col gap-3'>
              <input type="text" name="username" placeholder="Name" maxlength="25" minlength="3" required="true" id="id_username"/>
              <input type="datetime-local" name="date" placeholder="Time" required="true" id="id_date"/>
              <input type="file" name="file" placeholder="File" required="true" id="id_file"/>
          </form>
        </div>
        <div className='flex w-full justify-end gap-2'>
          <button className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>Send</button>
        </div>
      </div>
  };
  
  const editItem = (item) => {
    handleOpen();
    currentChildren = 
      <div>
        <b className='flex w-full justify-center text-lg'>
          EDIT ITEM
        </b>  
        <div className='flex w-full justify-around g-4'>
          <form className='flex flex-col gap-3'>
              <input type="text" name="username" placeholder="Name" maxlength="25" minlength="3" required="true" id="id_username" value={item.user} />
              <input type="datetime-local" name="date" placeholder="Time" required="true" id="id_date" value={item.time_created} />
              <input type="text" name="file" placeholder="File" required="true" id="id_file" value={item.file} />
          </form>
        </div>
        <div className='flex w-full justify-end gap-2'>
          <button className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>Save</button>
        </div>
      </div>
  };

  return (
    <div className="p-10 flex flex-col gap-7 ">
      <header className="flex flex-row ">
        <div onClick={createItem} className="pt-2 pb-2 pl-3 pr-3 border-2 rounded hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Add new item</div>
      </header>
      <main className=" flex flex-col flex-auto flex-wrap gap-2">
        {renderItems()}
      </main>
      <Modal isOpen={isModal} onClose={handleClose} children={currentChildren}>
        
      </Modal>
    </div>
  );
}

export default App;

Once again, do not bother to investigate that piece of code; it is going to be replaced in a next chapter. Just like that.

Combining React and Django

Axios or fetch ?

After finishing up with the backend and frontend parts we must combine them in some way. For that matter, I suggest using javascript library axios.
Why not fetch, but axios ?
I personally choose axios because of syntax; it is just less code to type. And one more reason he supports older browsers and older versions of them. So … Here I will attach a table for comparison between them; for that reason you could decide for yourself, what best fits you. Also, you will see in the next chapters of this article examples of usage for both of them.
Feature fetch axios
Availability Built-in Requires installation (axios package)
Syntax Verbose, more boilerplate Concise, user-friendly
JSON Handling Manual parsing with .json() Automatic parsing
Error Handling Requires manual handling Better built-in error handling
Interceptors Not available Available
Request Cancellation Not available Available
Browser Support Modern browsers only Better compatibility with older browsers
Let’s install and set up an axios library

npm install axios
After installing, in a package.json file you may add a proxy for a server. Insert it:

"proxy": "http://localhost:8000",
It is optional, but as a benefit, when we will be making requests, we no longer have to type the full address of a server. Less code, less errors.
Now all that remains is to decide where and from where we are going to access the API of our application.

Changing the code of App.js step-by-step

Imports and variables

Firstly, let’s add function useEffect in import. Secondly, let’s import the axios library. Thirdly, delete the items list. At the end, we will have only 3 imports, just like that:


import React, { useEffect, useState, useCallback } from 'react';
import Modal from './Modal';
import axios from "axios";

All of the remaining pieces of code will be pasted into an app function


function App() {
    …
}

At the beginning of a function, declare all needed variables as a React state. With callbacks to change their states as it will be needed later.


const [isModal, setOpen] = useState(false);
const [isUpdate, setUpdateTrigger] = useState(true);
const [itemsData, setItemsData] = useState(null);
const [formData, setFormData] = useState({
  username: "",
  datetime: "",
  file: null,
})
const [formBody, setFormBody] = useState(null);

Modal window

For opening and closing a modal window, let’s add the next functions:


const handleClose = () => {
  setOpen(false);
};
const handleOpen =() => {
  setOpen(true);
};

They are working in such a way that changing a isModal variable will cause visibility of the modal window.

List rendering

Let’s paste a code that is going to render our list of data accepted from a server. This code is going to be pasted at the end of the app function.


return (
  <div className="p-10 flex flex-col gap-7 ">
    <header className="flex flex-row ">
      <div onClick={createItem} className="pt-2 pb-2 pl-3 pr-3 border-2 rounded hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Add new item</div>
    </header>
    <main className=" flex flex-col flex-auto flex-wrap gap-2">
    {/* Place for a list of displaying items  */}
    {itemsData ? (itemsData.map((item) => (
      <div className="flex flex-row pl-4 h-8 border-2 rounded bg-amber-100">
        <div className="flex-grow">
          {item.user+'__'+item.file}
        </div>
        <div className="flex">
          <div onClick={()=> editItem(item)} className="bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Edit</div>
          <div onClick={()=> deleteItem(item)} className="bg-orange-300 pl-3 pr-3 hover:bg-orange-50 active:scale-150 hover:cursor-pointer transition-transform">Delete</div>
        </div>
      </div>
    ))) : (<p>Loading...</p>)
    }
    </main>
    {/* Place for modal window */}
    <Modal isOpen={isModal} onClose={handleClose} children={formBody}>
    </Modal>
  </div>
);

Rendering modal window, CRUD operations

As you can see in the rendering template above, there are functions such as:
  • createItem
  • editItem
  • deleteItem
The idea of those functions is simple. While pushing one of the buttons, which has a corresponding callback, they are going to paste a specific form`s code into the Modal component. Forms code is depending on what kind of operation you want to proceed with.


const deleteItem = (item) => {
  handleOpen();
  setFormBody(
  <div className='flex flex-col justify-between h-full gap-9'>
    <b className='flex w-full justify-center text-lg'>
      DELETE ITEM
    </b>  
    <div className='flex w-full justify-center'>
      Are you sure ?
    </div>
    <div className='flex w-full justify-center gap-2'>
      <button onClick={ () => deletionSubmit(item) } className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>Yes</button>
      <button onClick={handleClose} className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>No</button>
    </div>
  </div>)
};



const createItem = () => {
  handleOpen();
  
  setFormBody( 
    <div>
      <b className='flex w-full justify-center text-lg'>
        ADD NEW ITEM
      </b>  
      <div className='flex w-full justify-around g-4'>
        <form className='forma flex flex-col gap-3' onSubmit={creationSubmit} encType="multipart/form-data">
            <input type="text" name="username" placeholder="Name" onChange={handleChange}/>
            <input type="datetime-local" name="date" placeholder="Time" onChange={handleChange}/>
            <input type="file" name="file" placeholder="File" onChange={handleChange}/>
            <button className='flex justify-end' type="submit">
              <div className='bg-slate-200 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform pl-3 pr-3'>
                Submit
              </div>
            </button>
        </form>
      </div>
    </div>
  )
};



const editItem = (item) => {
  handleOpen();
  setFormBody( 
    <div>
      <b className='flex w-full justify-center text-lg'>
        EDIT ITEM
      </b>  
      <div className='flex w-full justify-around g-4'>
        <form id={item.id} className='flex flex-col gap-3' onSubmit={editingSubmit}>
            <input type="text" name="username" defaultValue={item.user}  onChange={handleChange} />
            <input type="datetime-local" name="date" defaultValue={item.time_created}  onChange={handleChange} />
            <input type="file" name="file" placeholder='File'  onChange={handleChange}/>
            <button className='flex justify-end' type="submit">
              <div className='bg-slate-200 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform pl-3 pr-3'>
                Submit
              </div>
            </button>
        </form>
      </div>
    </div>)
};

You should paste them somewhere above the return keyword.

Refreshing forms data

In my forms, the handleChange function is responsible for updating the data.


const handleChange = (e) => {
    if (e.target.name === 'file') {
      formData.file = e.target.files[0]
      setFormData(formData)
    } else if (e.target.name === 'username') {
      formData.username = e.target.value
      setFormData(formData)
    } else if (e.target.name === 'date') {
      formData.datetime = e.target.value
      setFormData(formData)
    }
}

Communication with a server

The next functions are corresponding for sending requests to the server:
  • editingSubmit
  • creationSubmit
  • deletionSubmit
And basically they are using the axios library of fetch API
The createSubmit function sends POST requests to /api/results/. It saves and sends the entered data, and at the end of execution it starts updating the data list.
axios
fetch

const creationSubmit = (form_el) =>{
  form_el.preventDefault()

  var form_data = new FormData();
  form_data.append("user", formData.username)
  form_data.append("time_created", formData.datetime)
  form_data.append("file", formData.file)

  // Use the fetch API to send the form data to the server  
  axios.post('/api/results/', form_data)
  .then(data => {
      console.log('Success:', data);
      setUpdateTrigger(true)
  })
  .catch(error => {
      console.error('Error:', error);
  });

  handleClose()
};
        

const creationSubmit = (form_el) =>{
    form_el.preventDefault()

    var form_data = new FormData();
    form_data.append("user", formData.username)
    form_data.append("time_created", formData.datetime)
    form_data.append("file", formData.file)

    fetch(`http://localhost:8000/api/results/`,{
      method: 'POST',
      headers: {
        'Accept': 'application/json',
      },
      body: form_data
    })
    .then( response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      console.log('Success');
      setUpdateTrigger(true)
    })
    .catch(error => {
        console.error('There was a problem with your fetch operation:', error);
    });

    handleClose()
};
        
The editingSubmit function sends PUT requests to /api/results/{ID} . It saves and sends the entered data, and at the end of execution it starts updating the data list.
axios
fetch

const editingSubmit = (form_el) => {
        console.log(form_el)
        form_el.preventDefault()
    
        var form_data = new FormData();
        form_data.append("user", formData.username)
        form_data.append("time_created", formData.datetime)
        form_data.append("file", formData.file)
    
        // Use the fetch API to send the form data to the server  
        axios.put(`/api/results/${form_el.target.id}/`, form_data)
        .then(data => {
            console.log('Success:', data);
            setUpdateTrigger(true)
        })
        .catch(error => {
            console.error('Error:', error);
        });
    
        handleClose()
}
        

const editingSubmit = (form_el) => {
        console.log(form_el)
        form_el.preventDefault()
    
        var form_data = new FormData();
        form_data.append("user", formData.username)
        form_data.append("time_created", formData.datetime)
        form_data.append("file", formData.file)
    
        fetch(`http://localhost:8000/api/results/${form_el.target.id}/`,{
          method: 'PUT',
          headers: {
            'Accept': 'application/json',
          },
          body: form_data
        })
        .then( response => {
          if (!response.ok) {
            throw new Error('Network response was not ok');
          }
          console.log('Success');
          setUpdateTrigger(true)
        })
        .catch(error => {
            console.error('There was a problem with your fetch operation:', error);
        });
    
        handleClose()
}
        
The deletionSubmit is sending DELETE requests to /api/results/{ID} . And because of that, removing data records by ID. At the end of execution, it starts updating the data list.
axios
fetch

const deletionSubmit = (item) => {
        axios.delete(`/api/results/${item.id}/`)
          .then((res) => setUpdateTrigger(true));
        handleClose()
}
        

const deletionSubmit = (item) => {
        fetch(`http://localhost:8000/api/results/${item.id}/`,{
          method: "DELETE",
          headers: {
            'Accept': 'application/json',
          }
        })
        .then( response => {
          if (!response.ok) {
            throw new Error('Network response was not ok');
          }
          setUpdateTrigger(true)
        })
        .catch(error => {
            console.error('There was a problem with your fetch operation:', error);
        });
        
        handleClose()
}
        

Data list refreshing

Up to this point, I wrote about how functions trigger list updates. What's the matter. The problem is in the useEffect function. In my case, this function calls handleUpdate only when the isUpdate state variable (see above) has changed. And it changes in the functions of deletion, changing, and adding records to the database.
axios
fetch

const handleUpdate = () => {
        axios.get('/api/results/')
            .then(response => {
                setItemsData(response.data); // Save the data in state  
            })
            .catch(error => {
                console.error('There was an error fetching the data!', error);
            });
        setUpdateTrigger(false)
};
        

const handleUpdate = () => {
        fetch('http://localhost:8000/api/results/',{
          method: 'GET',
          headers: {
            'Accept': 'application/json',
          },
        })
        .then( response => {
          if (!response.ok) {
            throw new Error('Network response was not ok');
          }
          return response.json(); 
        })
        .then(data => {
          const dataArray = Array.isArray(data) ? data : [data];
          setItemsData(dataArray); // Save the data in state  
        })
        .catch(error => {
            console.error('There was a problem with your fetch operation:', error);
        });
        setUpdateTrigger(false)
};
        
Insert the useEffect function before the beginning of a return keyword.

useEffect(handleUpdate, [isUpdate]);
If you use the useEffect function without a list of dependencies (i.e., isUpdate in our case), react will send requests to update the list constantly, which of course puts a lot of pressure on the server.
That's all for today. The React application is ready and is successfully communicating with the website backend.

Full source code for App.js

[Раскрыть] Chevron
axios
fetch

                
import React, { useEffect, useState } from 'react';
import Modal from './Modal';
import axios from "axios";

function App() {
  const [isModal, setOpen] = useState(false);
  const [isUpdate, setUpdateTrigger] = useState(true);
  const [itemsData, setItemsData] = useState(null);
  const [formData, setFormData] = useState({
    username: "",
    datetime: "",
    file: null,
  })
  const [formBody, setFormBody] = useState(null);

  // Is going to close modal window 
  const handleClose = () => {
    setOpen(false);
  };
 
  // Is going to open modal window 
  const handleOpen =() => {
    setOpen(true);
  };

  // Is going to updating formdata 
  const handleChange = (e) => {
    if (e.target.name === 'file') {
      formData.file = e.target.files[0]
      setFormData(formData)
    } else if (e.target.name === 'username') {
      formData.username = e.target.value
      setFormData(formData)
    } else if (e.target.name === 'date') {
      formData.datetime = e.target.value
      setFormData(formData)
    }

  }

  // Is going to get all data from server
  const handleUpdate = () => {
    axios.get('/api/results/')
        .then(response => {
            setItemsData(response.data); // Save the data in state  
        })
        .catch(error => {
            console.error('There was an error fetching the data!', error);
        });
    setUpdateTrigger(false)
  };

  // Send a delete request and update list for user 
  const deletionSubmit = (item) => {
    axios.delete(`/api/results/${item.id}/`)
      .then((res) => setUpdateTrigger(true));
    handleClose()
  }

  // Paste in modal window delete form 
  const deleteItem = (item) => {
    handleOpen();
    setFormBody(
    <div className='flex flex-col justify-between h-full gap-9'>
      <b className='flex w-full justify-center text-lg'>
        DELETE ITEM
      </b>  
      <div className='flex w-full justify-center'>
        Are you sure ?
      </div>
      <div className='flex w-full justify-center gap-2'>
        <button onClick={ () => deletionSubmit(item) } className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>Yes</button>
        <button onClick={handleClose} className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>No</button>
      </div>
    </div>)
  };
  
  // Send a post request with form data to create a new record in database
  const creationSubmit = (form_el) =>{
    form_el.preventDefault()

    var form_data = new FormData();
    form_data.append("user", formData.username)
    form_data.append("time_created", formData.datetime)
    form_data.append("file", formData.file)

    // Use the fetch API to send the form data to the server  
    axios.post('/api/results/', form_data)
    .then(data => {
        console.log('Success:', data);
        setUpdateTrigger(true)
    })
    .catch(error => {
        console.error('Error:', error);
    });

    handleClose()
  };

  // Paste in modal window create form 
  const createItem = () => {
    handleOpen();
    
    setFormBody( 
      <div>
        <b className='flex w-full justify-center text-lg'>
          ADD NEW ITEM
        </b>  
        <div className='flex w-full justify-around g-4'>
          <form className='forma flex flex-col gap-3' onSubmit={creationSubmit} encType="multipart/form-data">
              <input type="text" name="username" placeholder="Name" onChange={handleChange}/>
              <input type="datetime-local" name="date" placeholder="Time" onChange={handleChange}/>
              <input type="file" name="file" placeholder="File" onChange={handleChange}/>
              <button className='flex justify-end' type="submit">
                <div className='bg-slate-200 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform pl-3 pr-3'>
                  Submit
                </div>
              </button>
          </form>
        </div>
      </div>
    )
  };
  
  // Send a put request with form data to change existing a record in database 
  const editingSubmit = (form_el) => {
    console.log(form_el)
    form_el.preventDefault()

    var form_data = new FormData();
    form_data.append("user", formData.username)
    form_data.append("time_created", formData.datetime)
    form_data.append("file", formData.file)

    // Use the fetch API to send the form data to the server  
    axios.put(`/api/results/${form_el.target.id}/`, form_data)
    .then(data => {
        console.log('Success:', data);
        setUpdateTrigger(true)
    })
    .catch(error => {
        console.error('Error:', error);
    });

    handleClose()
  }

  // Paste in modal window edit form 
  const editItem = (item) => {
    handleOpen();
    setFormBody( 
      <div>
        <b className='flex w-full justify-center text-lg'>
          EDIT ITEM
        </b>  
        <div className='flex w-full justify-around g-4'>
          <form id={item.id} className='flex flex-col gap-3' onSubmit={editingSubmit}>
              <input type="text" name="username" defaultValue={item.user}  onChange={handleChange} />
              <input type="datetime-local" name="date" defaultValue={item.time_created}  onChange={handleChange} />
              <input type="file" name="file" placeholder='File'  onChange={handleChange}/>
              <button className='flex justify-end' type="submit">
                <div className='bg-slate-200 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform pl-3 pr-3'>
                  Submit
                </div>
              </button>
          </form>
        </div>
      </div>)
  };

  // Updating list of items when isUpdate is changed 
  useEffect(handleUpdate, [isUpdate]);

  return (
    <div className="p-10 flex flex-col gap-7 ">
      <header className="flex flex-row ">
        <div onClick={createItem} className="pt-2 pb-2 pl-3 pr-3 border-2 rounded hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Add new item</div>
      </header>
      <main className=" flex flex-col flex-auto flex-wrap gap-2">
      {/* Place for a list of displaying items  */}
      {itemsData ? (itemsData.map((item) => (
        <div className="flex flex-row pl-4 h-8 border-2 rounded bg-amber-100">
          <div className="flex-grow">
            {item.user+'__'+item.file}
          </div>
          <div className="flex">
            <div onClick={()=> editItem(item)} className="bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Edit</div>
            <div onClick={()=> deleteItem(item)} className="bg-orange-300 pl-3 pr-3 hover:bg-orange-50 active:scale-150 hover:cursor-pointer transition-transform">Delete</div>
          </div>
        </div>
      ))) : (<p>Loading...</p>)
      }
      </main>
      {/* Place for modal window */}
      <Modal isOpen={isModal} onClose={handleClose} children={formBody}>
      </Modal>
    </div>
  );
}

export default App;
                
                

                
import React, { useEffect, useState } from 'react';
import Modal from './Modal';
import axios from "axios";

function App() {
  const [isModal, setOpen] = useState(false);
  const [isUpdate, setUpdateTrigger] = useState(true);
  const [itemsData, setItemsData] = useState(null);
  const [formData, setFormData] = useState({
    username: "",
    datetime: "",
    file: null,
  })
  const [formBody, setFormBody] = useState(null);

  // Is going to close modal window 
  const handleClose = () => {
    setOpen(false);
  };
 
  // Is going to open modal window 
  const handleOpen =() => {
    setOpen(true);
  };

  // Is going to updating formdata 
  const handleChange = (e) => {
    if (e.target.name === 'file') {
      formData.file = e.target.files[0]
      setFormData(formData)
    } else if (e.target.name === 'username') {
      formData.username = e.target.value
      setFormData(formData)
    } else if (e.target.name === 'date') {
      formData.datetime = e.target.value
      setFormData(formData)
    }

  }

  // Is going to get all data from server
  const handleUpdate = () => {
    fetch('http://localhost:8000/api/results/',{
      method: 'GET',
      headers: {
        'Accept': 'application/json',
      },
    })
    .then( response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.json(); 
    })
    .then(data => {
      const dataArray = Array.isArray(data) ? data : [data];
      setItemsData(dataArray); // Save the data in state  
    })
    .catch(error => {
        console.error('There was a problem with your fetch operation:', error);
    });
    setUpdateTrigger(false)
  };

  // Send a delete request and update list for user 
  const deletionSubmit = (item) => {
    fetch(`http://localhost:8000/api/results/${item.id}/`,{
      method: "DELETE",
      headers: {
        'Accept': 'application/json',
      }
    })
    .then( response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      setUpdateTrigger(true)
    })
    .catch(error => {
        console.error('There was a problem with your fetch operation:', error);
    });
    
    handleClose()
  }

  // Paste in modal window delete form 
  const deleteItem = (item) => {
    handleOpen();
    setFormBody(
    <div className='flex flex-col justify-between h-full gap-9'>
      <b className='flex w-full justify-center text-lg'>
        DELETE ITEM
      </b>  
      <div className='flex w-full justify-center'>
        Are you sure ?
      </div>
      <div className='flex w-full justify-center gap-2'>
        <button onClick={ () => deletionSubmit(item) } className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>Yes</button>
        <button onClick={handleClose} className='bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform'>No</button>
      </div>
    </div>)
  };
  
  // Send a post request with form data to create a new record in database
  const creationSubmit = (form_el) =>{
    form_el.preventDefault()

    var form_data = new FormData();
    form_data.append("user", formData.username)
    form_data.append("time_created", formData.datetime)
    form_data.append("file", formData.file)

    fetch(`http://localhost:8000/api/results/`,{
      method: 'POST',
      headers: {
        'Accept': 'application/json',
      },
      body: form_data
    })
    .then( response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      console.log('Success');
      setUpdateTrigger(true)
    })
    .catch(error => {
        console.error('There was a problem with your fetch operation:', error);
    });

    handleClose()
  };

  // Paste in modal window create form 
  const createItem = () => {
    handleOpen();
    
    setFormBody( 
      <div>
        <b className='flex w-full justify-center text-lg'>
          ADD NEW ITEM
        </b>  
        <div className='flex w-full justify-around g-4'>
          <form className='forma flex flex-col gap-3' onSubmit={creationSubmit} encType="multipart/form-data">
              <input type="text" name="username" placeholder="Name" onChange={handleChange}/>
              <input type="datetime-local" name="date" placeholder="Time" onChange={handleChange}/>
              <input type="file" name="file" placeholder="File" onChange={handleChange}/>
              <button className='flex justify-end' type="submit">
                <div className='bg-slate-200 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform pl-3 pr-3'>
                  Submit
                </div>
              </button>
          </form>
        </div>
      </div>
    )
  };
  
  // Send a put request with form data to change existing a record in database 
  const editingSubmit = (form_el) => {
    console.log(form_el)
    form_el.preventDefault()

    var form_data = new FormData();
    form_data.append("user", formData.username)
    form_data.append("time_created", formData.datetime)
    form_data.append("file", formData.file)

    fetch(`http://localhost:8000/api/results/${form_el.target.id}/`,{
      method: 'PUT',
      headers: {
        'Accept': 'application/json',
      },
      body: form_data
    })
    .then( response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      console.log('Success');
      setUpdateTrigger(true)
    })
    .catch(error => {
        console.error('There was a problem with your fetch operation:', error);
    });

    handleClose()
  }

  // Paste in modal window edit form 
  const editItem = (item) => {
    handleOpen();
    setFormBody( 
      <div>
        <b className='flex w-full justify-center text-lg'>
          EDIT ITEM
        </b>  
        <div className='flex w-full justify-around g-4'>
          <form id={item.id} className='flex flex-col gap-3' onSubmit={editingSubmit}>
              <input type="text" name="username" defaultValue={item.user}  onChange={handleChange} />
              <input type="datetime-local" name="date" defaultValue={item.time_created}  onChange={handleChange} />
              <input type="file" name="file" placeholder='File'  onChange={handleChange}/>
              <button className='flex justify-end' type="submit">
                <div className='bg-slate-200 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform pl-3 pr-3'>
                  Submit
                </div>
              </button>
          </form>
        </div>
      </div>)
  };

  // Updating list of items when isUpdate is changed 
  useEffect(handleUpdate, [isUpdate]);

  return (
    <div className="p-10 flex flex-col gap-7 ">
      <header className="flex flex-row ">
        <div onClick={createItem} className="pt-2 pb-2 pl-3 pr-3 border-2 rounded hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Add new item</div>
      </header>
      <main className=" flex flex-col flex-auto flex-wrap gap-2">
      {/* Place for a list of displaying items  */}
      {itemsData ? (itemsData.map((item) => (
        <div className="flex flex-row pl-4 h-8 border-2 rounded bg-amber-100">
          <div className="flex-grow">
            {item.user+'__'+item.file}
          </div>
          <div className="flex">
            <div onClick={()=> editItem(item)} className="bg-slate-200 pl-3 pr-3 hover:bg-slate-50 active:scale-150 hover:cursor-pointer transition-transform">Edit</div>
            <div onClick={()=> deleteItem(item)} className="bg-orange-300 pl-3 pr-3 hover:bg-orange-50 active:scale-150 hover:cursor-pointer transition-transform">Delete</div>
          </div>
        </div>
      ))) : (<p>Loading...</p>)
      }
      </main>
      {/* Place for modal window */}
      <Modal isOpen={isModal} onClose={handleClose} children={formBody}>
      </Modal>
    </div>
  );
}

export default App;
                
                

Conclusion

Of course, I didn’t talk about how to deploy this project to the server, or how react will interact with django templates. Of course, there will be separate articles for them and everything will settle down over time. That’s all for today.
All source code can be found on github, name of branch is simple-integration-react-django https://github.com/DmRafaule/SearchResultParser/tree/simple-integration-react-django

Comments

(0)

captcha
Send
It's empty now. Be the first (o゚v゚)ノ

Other

Similar articles


Create basic, testing React app via CLI

Clock
19.07.2024
An eye
55
Hearts
0
Connected dots
0
Connected dots
0
Connected dots
0
Describing how to create basic/testing React app in terminal. Also checking for errors tests.

How to combine React with Django p. 1

Clock
03.08.2024
An eye
100
Hearts
0
Connected dots
0
Connected dots
0
Connected dots
0
In this article, you will know the way to integrate the React framework into a Django project. As a result, you will get a full-stack app/website. Also in the article, …

A new project, codename: SearchResultParser | Tim the Webmaster

Clock
16.07.2024
An eye
73
Hearts
0
Connected dots
0
Connected dots
0
Connected dots
0
I will be busy developing a new project. His name is SearchResultParser. Its essence is to parse data from the search results of various search engines, such as google, youtube, …

Django restframework, how to add and how to use

Clock
24.02.2025
An eye
99
Hearts
1
Connected dots
0
Connected dots
0
Connected dots
0
This article describes the process of setting up and adding a REST framework to a site written in Django. It is added in order to build an API for access …

Used termins


Related questions