iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
📝

Data Integration between Frontend and Backend using React + Django + CORS

に公開

Overview

As part of a personal development project I have resumed, I am rebuilding the previously implemented environment from scratch.
In doing so, I adopted a technology stack that is often used in enterprise-level application development, and I am writing this article both as a personal memo and to share my findings.
Assuming JSON is used as the data exchange method, the flow is as follows: define the data structure on the backend, then receive and display the generated data on the frontend.

Features Implemented

  • Displaying data using React
  • Building a Django Model Moved to another article (see below)
  • Frontend/backend data integration using CORS
No. Article
1 Frontend/Backend Data Integration Using React + Django + CORS (this article)
2 Customizing the Django Admin Interface (to be published later)
3 Data Integration Between an API Server Using Django REST Framework (DRF) and React (to be published later)
4 Referencing Foreign Key Models Using Django REST Framework Serializers (to be published later)
5 Verification of Asynchronous Communication Using React + Redux / Redux Toolkit (to be published later)
6 Implementing CRUD with Django Using the API Testing Tool "Postman" (Design Phase) (to be published later)
7 Implementing CRUD with Django Using the API Testing Tool "Postman" (Implementation Phase) (to be published later)

References

  • Routing Using React Router

https://qiita.com/jima-r20/items/c7d636262a9ebf0bedbd

  • Data Integration with CORS

https://qiita.com/shun198/items/9ebf19d8fd2c412396dd

https://morioh.com/a/18027196003c/react-json#google_vignette

  • VS Code Extension: Ascii Tree Generator
    • Not essential for implementation, but it helped with writing folder trees, so I made a note

https://marketplace.visualstudio.com/items?itemName=aprilandjan.ascii-tree-generator

Folder Structure

Below is a partial extract of the folders mainly used in this article.

  • Frontend (React / JavaScript)
[React Project]
├── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── BaseApp.css
    ├── BaseApp.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── reportWebVitals.js
    └── setupTests.js
├── .gitignore
├── package-lock.json
├── package.json
└── Readme.md
  • Backend (Python / Django)
[Django Project]
├── [Django Project_meta]
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── [Django App]
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── db.sqlite3
└── manage.py

Implementation Method

Frontend

Even though the React official site recommends React frameworks like Next.js, which allow implementing both frontend and backend together, this time I am using native React to let Django handle the backend functions.

React Project Folder
npx create-react-app my-app
cd my-app
npm start
  • Install required packages
React Project Folder
npm install axios

(Note)
If errors occur due to React version support, you can try the following:

  1. Use the --legacy-peer-deps option
    Add the --legacy-peer-deps option to the npm install command to ignore dependency conflicts.

    npm install axios --legacy-peer-deps
    
  2. Use the --force option
    You can also use the --force option to forcefully resolve dependency conflicts.

    npm install axios --force
    
  3. Modify package.json
    Manually add the dependency to package.json and try installing again.

    Then, install dependencies with the following command:

    npm install --legacy-peer-deps
    

This should install axios and resolve dependency conflicts. Try building the project again to check if the error is resolved.

  • In index.js, I created and loaded BaseApp.js instead of the default App.js.
src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import BaseApp from './BaseApp';
  :

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BaseApp />
  </React.StrictMode>
);

  :
  • Implementation of the data display screen
src/BaseApp.js
import React, { useState, useEffect } from "react";
import Axios from 'axios';

const BaseApp = () => {

  // Fetch JSON data
  const [projectList, setProjectList] = useState([]);

  const fetchData = async () => {
    const response = await Axios.get("http://localhost:8000/api/data");
    console.log(response);
    setProjectList(response.data);
  }

  useEffect(() => {
    fetchData();
  }, []);

  const filteredProjectList = projectList.filter((item) => {
    return item.id <= 3;
  });
  
  return (
    <div className="app">
      :
          <div className='section-wrapper'>
              {filteredProjectList.map((item) => (
                <dl key={item.id}>
                  <dt>{item.date}</dt>
                  <dd>{item.content}</dd>
                </dl>
              ))}
            </div>
          </div>

        </div>
      </div>
    </div>
  );
}

export default BaseApp;

For rendering, useState and useEffect are necessary. The mechanism asynchronously receives the backend data structure and displays it. The URL specified in Axios.get may vary depending on the Django settings described later.

Backend

# Create environment
conda create -n pythonenv python=3.11
 
# Connect to the created environment
conda activate pythonenv  # Set environment name

In the root directory of the backend folder, create two items: Django Project and Django App.
The directory structure is as follows:

  • Django Project: backend_django
  • Django App name: django_app
django-admin startproject [project name]
cd [project name]
python manage.py startapp [app name]
  • Initially, you need to migrate the models, so run the following in the root directory:
python manage.py makemigrations [app name]
python manage.py showmigrations [app name]  # Display migration list
python manage.py migrate [app name]
  • Start the Django server. The default IP will be used.
python manage.py runserver

This makes the preview available at http://localhost:8000/.

Frontend/Backend Data Integration Using CORS

  • In the root directory of the backend folder, install the package django-cors-headers to integrate the frontend and backend.
pip install django-cors-headers
  • Add CORS configuration settings in settings.py
backend_django/backend_django/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
      :
    '[Django App Name]',
    'corsheaders',  # Added to allow communication with the frontend
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',  # Added to allow communication with the frontend
    'django.middleware.security.SecurityMiddleware',
      :
]

# Added to allow communication with the frontend via CORS
CORS_ORIGIN_WHITELIST = [
    'http://localhost:3000',  # Frontend IP
]

  • Add app-specific URL definitions in project/urls.py
backend_django/backend_django/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path("api/", include("django_app.urls")),
]
  • Create app/urls.py
backend_django/django_app/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("data/", views.data, name="data"),
]
  • Define the data content in app/views.py
    • In this article, the data part is treated as JSON mock data.
backend_django/django_app/views.py
from django.shortcuts import render
from django.http import JsonResponse

def data(request):
  data = [
    {
      "id": 1,
      "date": "2022-10-01",
      "content": "【Test】[Project] \"Project Name 1\" deployed."
    },
    {
      "id": 2,
      "date": "2022-10-02",
      "content": "[Project] \"Project Name 2\" deployed."
    },
    {
      "id": 3,
      "date": "2022-10-03",
      "content": "[Project] \"Project Name 3\" deployed."
    },
    {
      "id": 4,
      "date": "2022-10-04",
      "content": "[Project] \"Project Name 4\" deployed."
    },
      :
  ]

  return JsonResponse(data, safe=False)

After these settings, the URL for the Python app
http://localhost:8000/api/data
becomes available.

Implementation View and Summary

Screenshot 2024-01-10 13.44.10.png

To integrate data using CORS, I found that it can be achieved by simply adding a package and making settings on the backend side at minimum.
Since both the frontend and backend use localhost here, both local servers need to be running. In a real production environment, you would likely replace this with a VPN or cloud server setup.
The final configuration is as follows:

  • Backend
    • Configure CORS in settings.py
    • Output (and define) JSON data in app/views.py for the frontend to reference
    • Define reference URLs in project/urls.py and app/urls.py
  • Frontend
    • Use the Axios package to fetch data from the backend URL
    • Filter the retrieved data and loop through it using map

Discussion