Интеграция React приложения в Django проект
Вступление
В этой статье, я покажу тебе, как интегрировать React в Django проект. Идея такой интеграции заключается в том, чтобы дать Джанге отрендерить свои шаблоны, чтобы после этого наше Реакт приложение перехватило отрендеренную страницу и модифицировало её.
Если ты хочешь пропустить базовую установку и настройку, переходи сразу к установке Реакта.
Так же ты можешь установить уже готовый базовый проект для этой главы. Если хочешь.
Создание Django проекта
Мы начнём с создания главной директории:
mkdir SearchResultParser
cd SearchResultParser
Теперь создадим и активируем виртуальное окружение:
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:
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 файлы и в таком виде отправляет через запросы.
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 файл и вставь следующий контент.
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
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 приложения 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;
После установки необходимых пакетов нужно настроить Babel. Создай файл настройки:
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 пакет, но сначала создадим настроечный файл):
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.
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 Rendered by Django, cooked by React
;
};
export default App;
const container = document.getElementById('app');
const root = createRoot(container);
root.render( );
Нам нужно подключить компонент App в index.js. Вставь это:
import App from './components/App';
И в конце концов, вставим код для нашего шаблонного файла app.html:
{% load static %}
React with Django
Теперь всё настроенно. Давай проверим работает ли? Запустим сервер django:
./manage.py runserver
И запустим react сервер:
npm run dev
Если всё сделанно правильно, ты увидишь что-то вроде этого
Заключение
Всё начинается с того что 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
Использованные термины
- HTML (Гипер текстовый язык разметки) ⟶ Это стандартный язык разметки, используемый для создания веб-страниц. Он описывает структуру и содержание документа с помощью различных элементов и тегов. HTML позволяет интегрировать текст, изображения, ссылки, формы и другие медиа-элементы.
- Виртуальное окружение ⟶ Это изолированная среда для выполнения программ, в которой можно устанавливать необходимые зависимости и библиотеки без влияния на систему в целом.
- CORS (Cross-Origin Resource Sharing) ⟶ Это механизм, который позволяет ограничить ресурсы веб-страниц, чтобы они могли запросить ресурсы с других доменов. Поскольку правила безопасности браузеров по умолчанию блокируют такие запросы (из-за политики одинаковых источников), CORS предоставляет способ более безопасного доступа к ресурсам с других источников.
- Фреймворк ⟶ Это предварительно определённая структура или основа, которая упрощает процесс разработки программного обеспечения. Фреймворки предоставляют разработчикам набор инструментов, библиотек и практик, позволяя создавать приложения более эффективно и организованно.
- Вебсайт ⟶ Это совокупность связанных между собой веб-страниц, доступных через интернет и имеющих одно общее доменное имя. Каждый веб-сайт может содержать текстовую информацию, изображения, видео и другие мультимедийные элементы. Веб-сайты могут выполнять различные функции, включая предоставление информации, общение, онлайн-торговлю и множество других взаимодействий.
Релевантные вопросы
- Мое приложение некорректно отображается на сервере? Если это не работает, в 99% случаев это проблема конфигурации. Отсутствующее свойство, неправильный порядок вызовов или отсутствующий компонент — серверный рендеринг строго относится к конфигурации. Лучший способ выяснить, что не так, — сравнить свой проект с уже работающей настройкой. Ознакомьтесь с эталонными реализациями по частям.
- Я не переношу язык шаблонов Django. Мне обязательно его использовать? Я думаю, что этот шаблонизатор — лучшее, что когда-либо было, но я знаю, что выбор языка шаблонов — это почти религия. В Django нет ничего, что требовало бы использования языка шаблонов, так что если вы привязаны к Jinja2, Mako или чему-то еще, то это нормально.
- Как использовать поля изображений и файлов? Использование FileField или ImageField в модели требует нескольких шагов: 1) В вашем файле настроек вам нужно будет определить MEDIA_ROOT 2) Добавить FileField или ImageField в вашу модель 3) Все, что будет храниться в вашей базе данных, — это путь к файлу (относительно MEDIA_ROOT)