Написать пост

Пишем приложение с бэкендом на Django и фронтендом на React

Аватар Типичный программист

Напишем приложение с бэкендом на Django и фронтендом на React. Создаём REST API на Джанго, добавляем React и соединяем в один проект.

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

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

  • как создать бэкенд с REST API на Django;
  • как добавить React в проект Django;
  • как соединить бэкенд на Django и фронт на React.
  1. Подготовка
  2. Создаём проект Django в виртуальном окружении Python
  3. Пишем приложение на Django
  4. Соединяем Django и React
  5. Устанавливаем React и webpack
  6. Готовим приложение Django для фронтенда
  7. Фронтенд на React
  8. Заключение

Подготовка

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

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

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

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

mkdir django-react && cd $_

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

			python3 -m venv venv
source venv/bin/activate
		

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

Установите зависимости Джанго и 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 — не исключение. Она может иметь одно или больше полей. Каждое поле соответствует полю в таблице.

Мы собираемся хранить контакты, поэтому модель 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

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

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

Существует масса туториалов по бэкенду на Джанго, начинающихся примерно так:

			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 в другой формат. После сериализации можно сохранить объект в файл или послать его через сеть.

Почему сериализация необходима? Модель Джанго — это класс 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 — класс сериализатора для модели.

Добавьте в файл django_react/views.py следующий код:

			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:

Пишем приложение с бэкендом на Django и фронтендом на React 1

Примечание в продакшене лучше отключить возможность просмотра 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:

			<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Django REST with React
</head>
<body>
<div id="app">
    <!-- React will load here -->
</div>
</body>
{% load static %}
<script src="{% static "frontend/main.js" %}"></script>
</html>
		

В шаблоне вызывается ./frontend/main.js — файл, который будет генерировать webpack, содержащий весь код на React.

Настроим маршрутизатор Django: включим туда url приложения frontend. Отредактируем файл ./project/urls.py:

			urlpatterns = [
    path('', include('leads.urls')),
    path('', include('frontend.urls')),
]
		

Создадим файл ./frontend/urls.py:

			from django.urls import path
from . import views


urlpatterns = [
    path('', views.index ),
]
		

Включим приложение фронтенда в список используемых приложений в файле ./project/settings.py:

			# Application definition

INSTALLED_APPS = [
    'leads.apps.LeadsConfig',
    'rest_framework',
    'frontend', # enable the frontend app
]
		

Зайдя на http://127.0.0.1:8000/, вы увидите пока что просто пустую страницу (для этого сервер Django должен продолжать работать).

Фронтенд на React

После бэкенда, написанного на Джанго, сделаем простой компонент React, который будет отображать наши данные. Если ваша база данных пуста, то самое время наполнить приложение какими-нибудь данными.

Запустите сервер Django и перейдите на http://127.0.0.1:8000/api/lead/ чтобы добавить контакты.

Создадим файл ./frontend/src/components/App.js. В нём будет компонент React, запрашивающий и отображающий данные.

			import React, { Component } from 'react';
import { render } from "react-dom";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [],
      loaded: false,
      placeholder: "Loading"
    };
  }

  componentDidMount() {
    fetch("api/lead")
      .then(response => {
        if (response.status > 400) {
          return this.setState(() => {
            return { placeholder: "Something went wrong!" };
          });
        }
        return response.json();
      })
      .then(data => {
        this.setState(() => {
          return {
            data,
            loaded: true
          };
        });
      });
  }

  render() {
    return (
      <ul>
        {this.state.data.map(contact => {
          return (
            <li key={contact.id}>
              {contact.name} - {contact.email}
            </li>
          );
        })}
      </ul>
    );
  }
}

export default App;

const container = document.getElementById("app");
render(<App />, container);
		

Примечание можно написать тот же компонент в виде функции с хуком useEffect.

Сохраните и закройте файл. Теперь создайте точку входа для webpack — файл ./frontend/src/index.js и импортируйте компонент:

import App from "./components/App";

Теперь можно протестировать результат. Запустите webpack:

npm run dev

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

python manage.py runserver

Перейдите на http://127.0.0.1:8000/. Если вы видите сообщение «Что-то пошло не так», то убедитесь, что применили миграции и заполнили базу данных. Вы должны увидеть данные, отображенные компонентом React.

Пишем приложение с бэкендом на Django и фронтендом на React 2

Выглядит просто. И работает!

Заключение

В этом материале мы сделали простой проект на Django REST API и React. Мы научились:

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

Если этот проект показался сложным, попробуйте другой туториал. В нём мы показали, как создать первое веб-приложение на Django.

Следите за новыми постами
Следите за новыми постами по любимым темам
99К открытий100К показов