Создаём веб-приложение с бэкендом на Django и фронтендом на React

@Tproger

Автор перевода Полина Ревякина, копирайтер в Skillbox

В этом материале вы узнаете:

  • как создать простое REST API на Django;
  • как добавить React в проект Django;
  • как соединить Django и React.

Подготовка

Вам понадобятся:

  • базовое понимание Python и Django;
  • базовое понимание JavaScript (и спецификации ECMAScript 2015) и React;
  • установленный Node.js.

Создаём проект Django в виртуальном окружении Python

Создайте новую папку и перейдите в неё:

mkdir django-react && cd $_

Потом активируйте виртуальное окружение Python:

python3 -m venv venv source venv/bin/activate

Примечание все следующие команды нужно выполнять из папки django-react и с активированным виртуальным окружением.

Установите зависимости Django и Django REST Framework:

pip install django djangorestframework

После установки создайте новый проект Django:

django-admin startproject django_react

Теперь сделаем простое API на Django для создания и хранения контактов.

Создаём приложение на Django

В каждом проекте Django может быть много приложений. Приложения можно делать переиспользуемыми: такими, что их можно добавить в менеджер пакетов Python и установить через него в другой проект, в котором нужно такое приложение.

Для создания нового приложения Django используется команда:

django-admin startapp app_name

где app_name — название приложения.

В нашем случае команда будет выглядеть так:

django-admin startapp leads

Она создаст приложение leads в папке django-react. Теперь структура папок в проекте должна выглядеть так:

(venv) your@prompt:~/Code/django-react$ tree -d -L 1 . ├── django_react ├── leads └── venv

Теперь сделаем так, чтобы Django проект использовал новое приложение. Откройте файл django_react/settings.py и добавьте приложение в INSTALLED_APPS:

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'leads.apps.LeadsConfig', # activate the new app ]

Создаём модель в базе данных с помощью Django

Модель — это объект, представляющий собой данные из таблицы. Почти каждый веб-фреймворк использует модели, и Django — не исключение.

Модель Django может иметь одно или больше полей. Каждое поле соответствует полю в таблице.

Мы собираемся хранить контакты, поэтому модель Lead может состоять из этих полей:

  • имя;
  • email;
  • сообщение.

(Можно добавлять и другие поля, например телефон). Добавим ещё поле с временем создания модели, потому что по умолчанию Django этого не делает.

Откроем leads/models.py и опишем модель Lead:

from django.db import models class Lead(models.Model): name = models.CharField(max_length=100) email = models.EmailField() message = models.CharField(max_length=300) created_at = models.DateTimeField(auto_now_add=True)

Примечаниеизучите документацию Django о полях. Когда придумываете структуру модели, выбирайте самые подходящие для вашего случая поля.

Создадим миграции командой:

python manage.py makemigrations leads

и применим их к базе данных:

python manage.py migrate

Займёмся тестированием

Вы могли подумать «А как же тестирование?».

Существует масса туториалов по Django, начинающихся примерно так:

class SomeModelModelTest(TestCase): def setUp(self): SomeModel.objects.create( name=fake.name(), email=fake.email(), phone=fake.phone_number(), message=fake.text(), source=fake.url() ) def test_save_model(self): saved_models = SomeModel.objects.count() self.assertEqual(saved_models, 2)

Не надо так. Нет никакого смысла ни в тестировании стандартной модели Django, ни в тестировании Django ORM. Что точно не нужно тестировать при создании приложения на Django:

  • встроенный код Django (модели, представления);
  • встроенные функции Python.

Не тестируйте то, что уже протестировано! Так что же тогда тестировать?

Добавили свой метод в модель Django — протестируйте его. Дополнили стандартное представление — протестируйте его. Но как узнать, что именно нужно протестировать?

Узнать это поможет библиотека coverage. Установите её:

pip install coverage

Теперь после каждого добавления или изменения кода запускайте coverage:

coverage run --source='.' manage.py test

и создавайте отчёт:

coverage html

Вы увидите, что именно нужно протестировать. Если предпочитаете увидеть отчёт в командной строке, запустите команду:

coverage report

Сериализаторы Django

Сериализация — это конвертация объекта Python в другой формат. После сериализации можно сохранить объект в файл или послать его через сеть.

Почему сериализация необходима? Модель Django — это класс Python. Чтобы превратить её в данные в формате JSON, нужна сериализация.

Сериализаторы работают и в обратном направлении: они конвертируют JSON в объекты. Это позволяет:

  • отображать модель Django в браузере с помощью конвертации в JSON;
  • делать запросы CRUD (create – read – update – delete) к API в формате JSON.

Суммируя: сериализаторы в Django можно использовать для совершения операций с моделями Django через API.

Создайте новый файл leads/serializers.py. Сериализатор LeadSerializer содержит нашу модель и поля:

from rest_framework import serializers from .models import Lead class LeadSerializer(serializers.ModelSerializer): class Meta: model = Lead fields = ('id', 'name', 'email', 'message')

Созданный дочерний класс от класса serializers.ModelSerializer. ModelSerializer в Django похож на ModelForm. Он подходит, когда нужно, чтобы сериализатор соответствовал модели.

Создаём представления

Если вы раньше работали с другими фреймворками, то можете удивиться, что в Django нет контроллеров.

Контроллеры содержат логику обработки запросов и возвращения ответов. В традиционной архитектуре MVC есть модель (Model), представление (View) и контроллер (Controller). Примеры MVC фреймворков: Rails (Ruby), Phoenix (Elixir), Laravel (PHP).

Django — это фреймворк MVT. MVT — это модель, представление и шаблон (Template). В Django есть много типов представлений: функции-представления, представления, основанные на классах, и обобщённые представления.

Используйте функции-представления только если изменение обобщенных представлений займет больше, чем написание представления заново.

Мы будем использовать обобщённые представления. Наше простое приложение будет:

  • возвращать выборку моделей;
  • создавать новые объекты в базе данных.

С помощью документации можно узнать, что есть представление для возвращения выборки и создания моделей: ListCreateAPIView. Это представление содержит queryset и serializer_class.

queryset — это выборка данных, которую приложение будет возвращать. В нашем случае — все модели Lead. serializer_class — класс сериализатора для модели.

from .models import Lead from .serializers import LeadSerializer from rest_framework import generics class LeadListCreate(generics.ListCreateAPIView): queryset = Lead.objects.all() serializer_class = LeadSerializer

С помощью трёх строк кода мы создали представление для обработки GET и POST запросов.

Чего ещё не хватает? Маршрутизации URL. Другими словами, нам нужно соединить URL и представления.

Настраиваем маршрутизацию url

Нам нужно сделать так, чтобы GET и POST запросы к api/lead/ обрабатывались представлением LeadListCreate, которое будет возвращать и создавать модели.

Чтобы настроить маршрутизацию URL, отредактируйте файл django_react/urls.py, добавив туда url приложения:

from django.urls import path, include urlpatterns = [ path('', include('leads.urls')), ]

Так мы указываем Django, что нужно использовать url, которые есть в приложения leads.

Теперь создайте файл leads/urls.py. В нём мы соединим представление LeadListCreate и url api/lead/:

from django.urls import path from . import views urlpatterns = [ path('api/lead/', views.LeadListCreate.as_view() ), ]

И наконец, включим rest_framework в INSTALLED_APPS. Откройте django_react/settings.py и добавьте приложение в INSTALLED_APPS:

# Application definition INSTALLED_APPS = [ # omitted for brevity 'leads.apps.LeadsConfig', 'rest_framework' ]

Запустим сервер Django:

python manage.py runserver

Перейдите по url http://127.0.0.1:8000/api/lead/ и вы увидите API:

Примечание в продакшене лучше отключить возможность просмотра API. Это можно сделать в конфигурации:

REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', ) }

Соединяем Django и React

У многих разработчиков возникают вопросы по поводу того, как правильно соединить Django и React.

Должен ли роутер React взять на себя маршрутизацию? Нужно ли монтировать компоненты React в каждом шаблоне Django?

Ответ зависит от случая.

Есть следующие способы создания проекта на Django и React (они похожи почти для любого веб-фреймворка):

  1. React в собственном приложении Django для фронтенда. Загружаем один HTML шаблон и даём React управление фронтендом (сложность: средняя).
  2. Django REST как отдельное API + React как отдельное SPA (сложность: высокая, нужна будет авторизация по JWT).
  3. Смешанный вариант: мини-приложения React в шаблонах Django (сложность: просто, но сложно будет поддерживать).

Если вы только начали работать с Django REST и React, избегайте варианта 2. Вместо этого выберите 1 (React в собственном приложении Django для фронтенда), если:

  • вы создаёте приложение, похожее на веб-сайт;
  • в интерфейсе будет много пользовательских действий, используется AJAX;
  • вас устраивает авторизация, основанная на сессиях;
  • вас не очень волнуют вопросы SEO;
  • вас устраивает роутер React.

Если будете держать React близко к Django, то будет проще с авторизацией. Можно будет использовать встроенную систему авторизации Django для регистрации и входа пользователей. Используйте старую добрую авторизацию с помощью сессий и не беспокойтесь о токенах и JWT.

Выберите вариант 3 (смешанный вариант: мини-приложения React в шаблонах Django), если:

  • на сайте не нужно использовать много JavaScript;
  • вам важно SEO и вы не можете использовать Node.js для рендеринга серверной части.

В данной статье мы будем использовать вариант 1.

Устанавливаем React и webpack

Создадим новое приложение Django для фронтенда:

django-admin startapp frontend

Вы увидите новую папку с названием frontend в вашей структуре папок:

(venv) your@prompt:~/Code/django-react$ tree -d -L 1 . ├── django_react ├── frontend ├── leads └── venv

Подготовим папки для хранения компонентов React:

mkdir -p ./frontend/src/components

И статики:

mkdir -p ./frontend/{static,templates}/frontend

Дальше установим React, webpack и babel. Перейдите в папку frontend и создайте окружение:

cd ./frontend && npm init -y

Установите webpack и webpack CLI:

npm i webpack webpack-cli --save-dev

Откройте package.json и запишите 2 скрипта для продакшна и для разработки:

"scripts": { "dev": "webpack --mode development ./src/index.js --output ./static/frontend/main.js", "build": "webpack --mode production ./src/index.js --output ./static/frontend/main.js" }

Сохраните и закройте файл.

Установим babel, чтобы код был совместим со старыми браузерами, которые не поддерживают последние стандарты JavaScript:

npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev

Установим React:

npm i react react-dom --save-dev

Настроим Babel (по-прежнему находясь в папке frontend):

{ "presets": [ "@babel/preset-env", "@babel/preset-react" ] }

Создадим файл webpack.config.js для настройки загрузчика babel:

module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] } };

Готовим приложение Django для фронтенда

Создадим представление в ./frontend/views.py:

from django.shortcuts import render def index(request): return render(request, 'frontend/index.html')

Создадим шаблон в ./frontend/templates/frontend/index.html:

Анализ
×