Интеграция React приложения в Django проект

Вступление

В этой статье, я покажу тебе, как интегрировать React в Django проект. Идея такой интеграции заключается в том, чтобы дать Джанге отрендерить свои шаблоны, чтобы после этого наше Реакт приложение перехватило отрендеренную страницу и модифицировало её.
Если ты хочешь пропустить базовую установку и настройку, переходи сразу к установке Реакта.
Так же ты можешь установить уже готовый базовый проект для этой главы. Если хочешь.

Создание Django проекта

Мы начнём с создания главной директории:
mkdir SearchResultParser
cd SearchResultParser    
Теперь создадим и активируем виртуальное окружение:
Linux
Windows
python -m venv .venv
source ./.venv/Scripts/activate
python -m venv .venv
.venv\Scripts\Activate.ps1    
После активации окружения, установим сам django и начнём новый проект. Назовём его Website.
pip install django
django-admin startproject Website
cd Website
Если всё сделано верно, мы сможем запустить наш базовый проект и убедиться в этом. Вот так:
./manage.py runserver

Создание Backend приложения

Теперь нужно установить парочку новых питоновских пакета, для корректной работы с API нашего сайта.
django-cors-headers: для активации так называемого Cross-Origin Resource Sharing (CORS) для общения React приложения и Django API.
djangorestframework: это Django приложение, которое позволит нам с лёгкостью построить АПИ для нашего сайта.
pip install djangorestframework django-cors-headers
Наконец создаём наше приложение
./manage.py startapp Backend
Отредактируй settings.py файл в своём любимом редакторе. В моём случае это будет NeoVim. Теперь подключим приложение Backend к нашему проекту.
nvim Backend/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'rest_framework',
    'Backend.apps.BackendConfig',
]

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',
]
Добавь это в конец файла settings.py
CORS_ORIGIN_WHITELIST = [
    'http://localhost:3000'
]
Создай файл urls.py:
Linux
Windows
touch Backend/urls.py           
Get-Item Backend/urls.py           
Вставь следующий контент в urls.py . Он находится в папке Website:
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from Backend import views

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
]
Мы импортировали роутеры для REST фреймворка и представления из ранее созданного приложения Backend, а потом подключили. А сейчас создадим временную модель:
nvim Backend/models.py
from django.db import models

class BackendModel(models.Model):
    title = models.CharField(max_length=120)
    description = models.TextField()

    def _str_(self):
        return self.title
Подключим нашу временную модель к админке django
nvim Backend/admin.py
from django.contrib import admin
from .models import  BackendModel

class BackendModelAdmin(admin.ModelAdmin):
    list_display = ('title', 'description')

admin.site.register(BackendModel, BackendModelAdmin)
Чтобы REST фреймворк работал, ему нужен сериализатор для модели. Он конвертирует django модели в JSON файлы и в таком виде отправляет через запросы.
Linux
Windows
touch Backend/serializers.py           
Get-Item Backend/serializers.py           
nvim Backend/serializers.py
from rest_framework import serializers
from .models import BackendModel

class BackendModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BackendModel
fields = ('id', 'title', 'description')
Последнее, что нам осталось сделать, так это сделать класс-представление для нашей временной модели, BackendModel.
nvim Backend/views.py
from django.shortcuts import render
from rest_framework import viewsets
from .serializers import BackendModelSerializer
from .models import  BackendModel

class BackendModelView(viewsets.ModelViewSet):
    serializer_class = BackendModelSerializer
    queryset = BackendModel.objects.all()
Создаём миграции и применяем их
./manage.py makemigrations
./manage.py migrate
Не забудь создать суперпользователя. Он в будущем пригодится.
./manage.py createsuperuser

Создание Frontend приложения

Настало время для создания Frontend приложения. Это приложение и будет содержать наше react приложение. Но сначала нужно создать django приложение, настроить и подключить его.
./manage.py startapp Frontend
nvim Website/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'rest_framework',
    'Backend.apps.BackendConfig',
    'Frontend.apps.FrontendConfig',
]

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',
]
Создай urls.py файл и вставь следующий контент.
Linux
Windows
touch Frontend/urls.py           
Get-Item Frontend/urls.py           
nvim Frontend/urls.py
from django.urls import path
from .views import main

urlpatterns = [
    path('', main, name='main')
]
Анологично и здесь. Нам нужно создать функцию main. Это временная функция, в будущем эта функция будет удалена.
nvim Frontend/views.py
from django.shortcuts import render

def main(request):
    return render(request, 'Frontend/app.html')
Чтобы django хоть что-нибудь отрисовал нужно будет создать шаблон.
mkdir Frontend/templates
mkdir Frontend/templates/Frontend
Linux
Windows
touch Frontend/templates/Frontend/app.html           
Get-Item Frontend/templates/Frontend/app.html           
Теперь подключим созданный ранее urls.py файл в Website/urls.py
nvim Website/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from Backend import views

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
    path('', include('Frontend.urls')),
]

Установка и настройка React

Настало время установить React. Не переживай, это просто если ты знаешь что нужно устанавливать) Зайдём в Frontend приложение и создадим несколько статических директорий там:
cd Frontend
mkdir static
Для хранения скриптов
mkdir static/js
Для хранения изображений
mkdir static/img
Для хранения стилей
mkdir static/css
Для хранения реакт компонентов
mkdir src
mkdir src/components
Шеврон Почему я не добавил Frontend директорию в static, как это обычно делают? Дело в том, что наш сайт может содержать несколько приложений и чтобы у все их был доступ к реакту мы не создаём данную директорию.
На данном шаге настройка и подготовка Frontend приложения Django завершена, перейдём к установке необходимых пакетов для react. Я надеюсь npm уже установлен?
npm init -y
Устанавливай пакеты один за другим.
webpack для объединения всего нашего JS кода
babel для перевода наших JS и CSS файлов в специфичный для каждого отдельного браузера.
react для разработки фронтенда
npm i webpack webpack-cli --save-dev ;
npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev ;
npm i react react-dom --save-dev ;
npm install @babel/plugin-proposal-class-properties ;
npm install react-router-dom;
Шеврон Не пытайся объединить все команды из оболочки в одну. Node.js не сможет с этим справиться одновременно.
После установки необходимых пакетов нужно настроить Babel. Создай файл настройки:
Linux
Windows
touch babel.config.json           
Get-Item babel.config.json           
Вставь этот кусок настроечного кода:
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "node": "10"
                }
            }
        ],
        "@babel/preset-react"
    ],
    "plugins": ["@babel/plugin-proposal-class-properties"]
}
Теперь настроим webpack пакет, но сначала создадим настроечный файл):
Linux
Windows
touch webpack.config.js           
Get-Item webpack.config.js           
const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "./static/js"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
    ],
  },
  optimization: {
    minimize: true,
  },
  plugins: [
    new webpack.DefinePlugin({
      "process.env": {
        // This has effect on the react lib size
        NODE_ENV: JSON.stringify("production"),
      },
    }),
  ],
};
Настроим файл package.json. Вставь этот кусочек кода в список scripts:
{
  "name": "frontend",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "webpack --mode development --watch",
    "prod": "webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@babel/preset-env": "^7.25.3",
    "@babel/preset-react": "^7.24.7",
    "babel-loader": "^9.1.3",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "webpack": "^5.93.0",
    "webpack-cli": "^5.1.4"
  },
  "dependencies": {
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "react-router-dom": "^6.25.1"
  }
}

Создавая первый react компонент

После того как мы всё настроили давай напишем немного react кода. В папке Frontend/src, создай файл index.js, а в папке Frontend/src/components, создай файл App.js.
Linux
Windows
touch src/index.js;
touch src/components/App.js;           
Get-Item src/index.js
Get-Item src/components/App.js           
Вставь данный код-пример в файл App.js
import React from 'react';
import { createRoot } from 'react-dom/client';

const App = () => {
    return <h1>Rendered by Django, cooked by React</h1>;
};

export default App;

const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
Нам нужно подключить компонент App в index.js. Вставь это:
import App from './components/App';
И в конце концов, вставим код для нашего шаблонного файла app.html:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React with Django</title>
</head>
<body>
    <div id="app"></div>
    <script src="{% static 'js/main.js' %}"></script>
</body>
</html>
Теперь всё настроенно. Давай проверим работает ли? Запустим сервер django:
./manage.py runserver
И запустим react сервер:
npm run dev
Если всё сделанно правильно, ты увидишь что-то вроде этого
Пример простого проекта на django и react

Заключение

Всё начинается с того что django отрисовывает шаблон. После чего react перехватывает эту страницу, находит элемент по id “app” и отрисовывает наш h1 тег. Теперь мы имеем готовый фулстек приложение готовое чтобы его доделали)
Если ты пропустил всё что было выше и хочешь просто готовое-к-использованию решение, то ты можешь скачать его здесь. Это архив с настроенной структурой директорий и готовыми зависимостями. Всё что тебе остаётся сделать, так это скачать, создать виртуальное окружение, установить все необходимые python и npm пакеты.
В следующей статье, я покажу базовую раскладку и интерфейс для нашего проекта. И как её сделать при помощи реакта.

Общие ошибки, баги и недоразумения

  • Неправильная структура проекта
    Ошибка: Неправильная организация каталога проекта, что приводит к путанице и трудностям в управлении кодовыми базами React и Django.
    Решение: Поддерживайте четкую и логичную структуру каталогов. Храните код для фронтенда и бэкенда в отдельных каталогах.
  • Игнорирование проблем CORS
    Ошибка: Игнорирование настроек Cross-Origin Resource Sharing (CORS), что может привести к блокировке запросов.
    Решение: Настройте проект Django для обработки CORS. Используйте django-cors-headers, чтобы разрешить определенные источники запросов.
  • Непоследовательная конфигурация среды
    Ошибка: Наличие конфликтующих или непоследовательных конфигураций среды, что приводит к проблемам в сборках разработки и производства.
    Решение: Убедитесь, что переменные среды определены последовательно. Используйте такие инструменты, как dotenv , для управления переменными среды как в React, так и в Django.
  • Неправильная обработка статических файлов
    Ошибка: Неправильная настройка обработки статических файлов, что может привести к проблемам при обслуживании ресурсов React в Django.
    Решение: Правильно настройте Django для обслуживания статических файлов и убедитесь, что ресурсы React размещены в каталоге, который Django может обслуживать.
  • Игнорирование конфликтов маршрутизации на стороне клиента
    Ошибка: Игнорирование потенциальных конфликтов между механизмами маршрутизации Django и React Router, что приводит к неработоспособным ссылкам или неправильной маршрутизации.
    Решение: Делегируйте клиентскую маршрутизацию React Router и убедитесь, что Django обслуживает приложение React для всех соответствующих маршрутов.

сердце
2
3 соединённые точки
1

Использованные термины

Релевантные вопросы

Похожие статьи

Новый проект: SearchResultParser | Тим Вебмастер

Часы
16.07.2024
Глазик
215
Сердечки
4
Соединённые точки
0
Буду занят разработкай нового проекта с кодовым названием SearchResultParser. Его суть в том, чтобы парсить данные из поисковой выдачи различных поисковых машин. Таких как google, youtube, yandex и прочих.