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

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

91770

Автор перевода Полина Ревякина, копирайтер в 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

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

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

Мнение: разработка через тестирование — это тупо. Обсуждаем TDD
tproger.ru

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

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

Как оценить профессионализм программиста за 5 вопросов — отвечают эксперты
tproger.ru

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

Веб-фреймворки для начинающих: простое объяснение с примерами
tproger.ru

Контроллеры содержат логику обработки запросов и возвращения ответов. В традиционной архитектуре 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:

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

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

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

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

React: практики, которые помогут стать продвинутым разработчиком
tproger.ru

Должен ли роутер 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:

			


  
  
  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></code>
		</pre><button class="tp-content-code__button" data-v-da581141><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" role="presentation" data-v-da581141><!----><g fill="inherit" stroke="inherit"><!--[--><!--[--><rect stroke="inherit" width="14.655" height="14.655" x="7.345" y="2.5" stroke-width="2" rx="1"></rect><path stroke="inherit" stroke-width="2" d="M4.897 6.569H4a2 2 0 0 0-2 2V20.5a2 2 0 0 0 2 2h12.655a2 2 0 0 0 2-2v-.896"></path><!--]--><!--]--></g></svg></button></div><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>В шаблоне вызывается <code class="">./frontend/main.js</code> — файл, который будет генерировать webpack, содержащий весь код на React.</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Настроим маршрутизатор Django: включим туда url приложения frontend. Отредактируем файл <code class="">./project/urls.py</code>:</p><!--]--><!--[--><div class="tp-content-code code-toolbar" data-type="code" data-v-da581141><pre class="tp-content-code__pre" data-v-da581141>			<code class="lang-python lazy-code" data-v-da581141>urlpatterns = [
    path('', include('leads.urls')),
    path('', include('frontend.urls')),
]</code>
		</pre><button class="tp-content-code__button" data-v-da581141><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" role="presentation" data-v-da581141><!----><g fill="inherit" stroke="inherit"><!--[--><!--[--><rect stroke="inherit" width="14.655" height="14.655" x="7.345" y="2.5" stroke-width="2" rx="1"></rect><path stroke="inherit" stroke-width="2" d="M4.897 6.569H4a2 2 0 0 0-2 2V20.5a2 2 0 0 0 2 2h12.655a2 2 0 0 0 2-2v-.896"></path><!--]--><!--]--></g></svg></button></div><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Создадим файл <code class="">./frontend/urls.py</code>:</p><!--]--><!--[--><div class="tp-content-code code-toolbar" data-type="code" data-v-da581141><pre class="tp-content-code__pre" data-v-da581141>			<code class="lang-python lazy-code" data-v-da581141>from django.urls import path
from . import views


urlpatterns = [
    path('', views.index ),
]</code>
		</pre><button class="tp-content-code__button" data-v-da581141><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" role="presentation" data-v-da581141><!----><g fill="inherit" stroke="inherit"><!--[--><!--[--><rect stroke="inherit" width="14.655" height="14.655" x="7.345" y="2.5" stroke-width="2" rx="1"></rect><path stroke="inherit" stroke-width="2" d="M4.897 6.569H4a2 2 0 0 0-2 2V20.5a2 2 0 0 0 2 2h12.655a2 2 0 0 0 2-2v-.896"></path><!--]--><!--]--></g></svg></button></div><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Включим приложение фронтенда в список используемых приложений в файле <code class="">./project/settings.py</code>:</p><!--]--><!--[--><div class="tp-content-code code-toolbar" data-type="code" data-v-da581141><pre class="tp-content-code__pre" data-v-da581141>			<code class="lang-python lazy-code" data-v-da581141># Application definition

INSTALLED_APPS = [
    'leads.apps.LeadsConfig',
    'rest_framework',
    'frontend', # enable the frontend app
]</code>
		</pre><button class="tp-content-code__button" data-v-da581141><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" role="presentation" data-v-da581141><!----><g fill="inherit" stroke="inherit"><!--[--><!--[--><rect stroke="inherit" width="14.655" height="14.655" x="7.345" y="2.5" stroke-width="2" rx="1"></rect><path stroke="inherit" stroke-width="2" d="M4.897 6.569H4a2 2 0 0 0-2 2V20.5a2 2 0 0 0 2 2h12.655a2 2 0 0 0 2-2v-.896"></path><!--]--><!--]--></g></svg></button></div><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Зайдя на http://127.0.0.1:8000/, вы увидите пока что просто пустую страницу (для этого сервер Django должен продолжать работать).</p><!--]--><!--[--><h2 id="part7" class="tp-content-subtitle tp-content-subtitle--h2" data-type="header2" data-v-75e770f1>Фронтенд на React</h2><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>После бэкенда, написанного на Джанго, сделаем простой компонент React, который будет отображать наши данные. Если ваша база данных пуста, то самое время наполнить приложение какими-нибудь данными.</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Запустите сервер Django и перейдите на http://127.0.0.1:8000/api/lead/ чтобы добавить контакты.</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Создадим файл <code class="">./frontend/src/components/App.js</code>. В нём будет компонент React, запрашивающий и отображающий данные.</p><!--]--><!--[--><div class="tp-content-code code-toolbar" data-type="code" data-v-da581141><pre class="tp-content-code__pre" data-v-da581141>			<code class="lang-javascript lazy-code" data-v-da581141>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);</code>
		</pre><button class="tp-content-code__button" data-v-da581141><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" role="presentation" data-v-da581141><!----><g fill="inherit" stroke="inherit"><!--[--><!--[--><rect stroke="inherit" width="14.655" height="14.655" x="7.345" y="2.5" stroke-width="2" rx="1"></rect><path stroke="inherit" stroke-width="2" d="M4.897 6.569H4a2 2 0 0 0-2 2V20.5a2 2 0 0 0 2 2h12.655a2 2 0 0 0 2-2v-.896"></path><!--]--><!--]--></g></svg></button></div><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f><u is="tp-badge" class="tp-badge tp-badge--first-variant" data-color="firstVariant">Примечание</u> можно написать тот же компонент в виде функции с хуком <code class="">useEffect</code>.</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Сохраните и закройте файл. Теперь создайте точку входа для webpack — файл <code class="">./frontend/src/index.js</code> и импортируйте компонент:</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f><code class="">import App from "./components/App"</code>;</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Теперь можно протестировать результат. Запустите webpack:</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f><code class="">npm run dev</code></p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Запустите сервер Django:</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f><code class="">python manage.py runserver</code></p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Перейдите на http://127.0.0.1:8000/. Если вы видите сообщение «Что-то пошло не так», то убедитесь, что применили миграции и заполнили базу данных. Вы должны увидеть данные, отображенные компонентом React.</p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f><a href="https://media.tproger.ru/uploads/2020/04/django-rest-react.png"></a></p><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Выглядит просто. И работает!</p><!--]--><!--[--><h2 id="part8" class="tp-content-subtitle tp-content-subtitle--h2" data-type="header2" data-v-75e770f1>Заключение</h2><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>В этом материале мы сделали простой проект на Django REST API и React. Мы научились:</p><!--]--><!--[--><ul class="tp-content-list" style="" data-type="list" data-v-705dc74d><!--[--><li class="tp-content-list__item" data-v-705dc74d>создавать простое REST API на Django;</li><li class="tp-content-list__item" data-v-705dc74d>добавлять React в проект Django;</li><li class="tp-content-list__item" data-v-705dc74d>соединять Django REST API и React.</li><!--]--></ul><!--]--><!--[--><div class="tp-content-plug-block" data-v-a8c2cb21><svg xmlns="http://www.w3.org/2000/svg" width="38" height="38" viewBox="0 0 24 24" role="presentation" class="tp-content-plug-block__icon" data-v-a8c2cb21><!----><g fill="inherit" stroke="inherit"><!--[--><path d="m12.856 14.837-1.84.001-.312-.555a1.067 1.067 0 0 0-1.001-.695H6.899c-.444 0-.844.275-1 .695l-.274.556H3.75a1.07 1.07 0 0 0-1.073 1.069v5.363a1.07 1.07 0 0 0 1.07 1.073h9.109c.59 0 1.069-.478 1.069-1.073l.002-5.364c0-.59-.48-1.07-1.07-1.07Zm-4.554 5.754A2.03 2.03 0 0 1 6.27 18.56a2.03 2.03 0 0 1 2.03-2.031 2.03 2.03 0 0 1 2.032 2.03 2.028 2.028 0 0 1-2.031 2.032Zm-1.07-9.68a.61.61 0 0 0 .443.186c.166 0 .33-.06.44-.186l3.745-3.898a2.798 2.798 0 0 0-.19-4.059c-1.07-.913-2.661-.747-3.643.269l-.385.395-.352-.396c-.981-1.016-2.573-1.182-3.643-.269-1.225 1.045-1.289 2.925-.195 4.059l3.78 3.9Zm14.117-8.553-5.805.89c-.571.087-.996.614-.996 1.24v4.167a3.351 3.351 0 0 0-.625-.066c-1.382 0-2.465.84-2.465 1.876 0 1.035 1.118 1.876 2.465 1.876 1.377 0 2.49-.836 2.5-1.867l.004-4.239 4.375-.669-.002 1.84a3.35 3.35 0 0 0-.625-.066c-1.381 0-2.464.84-2.464 1.875 0 1.04 1.118 1.84 2.465 1.84 1.377 0 2.49-.838 2.464-1.868v-5.63c.002-.725-.592-1.306-1.291-1.199Zm.703 14.362h-2.177l1.502-3.504a.625.625 0 0 0-.987-.716l-5 4.375a.624.624 0 0 0 .412 1.095h2.176l-1.501 3.504a.625.625 0 0 0 .207.751c.11.046.239.12.368.12a.623.623 0 0 0 .411-.154l5-4.375a.624.624 0 0 0-.411-1.096Z" data-v-a8c2cb21></path><!--]--></g></svg><div class="tp-content-plug-block__text" data-v-a8c2cb21><span class="tp-content-plug-block__title" data-v-a8c2cb21>На данный момент этот блок не поддерживается, но мы не забыли о нём!</span><span class="tp-content-plug-block__description" data-v-a8c2cb21>Наша команда уже занята его разработкой, он будет доступен в ближайшее время.</span></div><div class="tp-content-plug-block__easter-egg" data-v-a8c2cb21><svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" role="presentation" data-v-a8c2cb21><!----><g fill="inherit" stroke="none"><!--[--><!--[--><path fill="#7A5C44" d="M4 14a1.333 1.333 0 0 1-1.333-1.333v-10C2.667 1.93 3.263 2 4 2s1.333-.07 1.333.667c0 0-.404 4.282 0 7.998C5.693 13.98 8 14.667 8 14.667 8 15.403 4.737 14 4 14Zm9.333 3.333A1.333 1.333 0 0 1 12 15.999V2c0-.736.597-.666 1.333-.666.737 0 1.333-.07 1.333.666 0 0-.297 3.406-.083 6.198.213 2.792.083 7.802.083 7.802 0 .736-.596 1.334-1.333 1.334Z"></path><path fill="#662113" d="M24 2.667 0 5.333V2.667l24-1.334v1.334Z"></path><path fill="#A78E81" d="M15.096 12.27c-.422.751-.909 1.207-1.44 1.463-.268.027-.755-.057-.945-.962a21.46 21.46 0 0 1-.445-4.396c0-2.763.4-5.828.4-5.828 0-.62.942-.624 1.391-.661-.104-.555-1.166-.553-2.456-.553-.968 0-1.504.716-1.6 1.534-.099.818-.527 4.231-.497 6.666a56.18 56.18 0 0 0 .21 4.011c-.528-.134-1.057-.262-1.576-.327-1.871-.238-4.337-.357-4.753-3.921-.329-2.821-.052-6.083-.052-6.083 0-.619.942-.772 1.391-.808-.104-.555-1.119-.608-2.407-.522-.966.064-1.494.562-1.65 1.65C.415 5.286.385 9.325.533 12.117c.083 1.559.327 7.174 2.733 9.357 1.405 1.275 3.792 2.028 6.734 1.86 2.79-.16 5.082-1.198 6.365-2.276 2.228-1.871 2.727-3.225 2.82-4.69.148-2.368-3.172-5.729-4.089-4.097Z"></path><path fill="#A78E81" d="M23.35 15.114c-1.4 2.134-4.185 2.782-7.173.821-2.988-1.96-3.502-4.772-2.1-6.906 1.4-2.134 4.991-1.723 6.922-.416 1.93 1.306 3.752 4.367 2.351 6.501Z"></path><path fill="#E2D2C7" d="M22.18 15.452c-1 1.525-3.442 1.99-6.003.31-2.56-1.68-2.945-4.001-1.945-5.526 1-1.525 2.863-1.28 5.424.4 2.56 1.68 3.525 3.292 2.525 4.816Z"></path><path fill="#292F33" d="M13.71 9.71a4.22 4.22 0 0 0-.328 2.366c1 .293 2.425.647 3.1.506 1.098-.228 1.466-1.211 1.305-1.987-.224-1.078-2.128-1.696-4.077-.886Z"></path><path fill="#F5F8FA" d="M15.593 11.843a.792.792 0 1 0 0-1.584.792.792 0 0 0 0 1.584Z"></path><path fill="#292F33" d="M22.871 15.72a4.22 4.22 0 0 1-2.04 1.243c-.666-.799-1.558-1.967-1.699-2.642-.228-1.098.528-1.826 1.304-1.988 1.078-.223 2.403 1.277 2.435 3.388Z"></path><path fill="#F5F8FA" d="M20.892 15.32a.792.792 0 1 0 0-1.584.792.792 0 0 0 0 1.584Z"></path><path fill="#292F33" d="M18.698 14.983a1.584 1.584 0 1 1-2.65-1.738c.48-.732 1.029-.274 1.76.206.731.48 1.37.8.89 1.532Z"></path><path fill="#292F33" d="M18.653 16.748a.398.398 0 0 1-.05-.003c-2.985-.436-4.197-2.714-4.247-2.811a.333.333 0 0 1 .592-.307c.011.02 1.115 2.072 3.753 2.458a.334.334 0 0 1-.048.663Z"></path><!--]--><!--]--></g></svg></div></div><!--]--><!--[--><p class="tp-content-paragraph" data-type="paragraph" data-v-6c80349f>Если этот проект показался сложным, попробуйте другой туториал. В нём мы показали, <a href="https://tproger.ru/translations/create-your-first-django-app/">как создать первое веб-приложение на Django</a>.</p><!--]--><!--]--></div></div><div class="tp-post-page__end-beacon" data-v-a1103d06></div><div class="tp-post-page__container-tags" data-v-a1103d06><div class="tp-tag-subscription-banner" data-v-a1103d06 data-v-4c97ca31><div class="tp-tag-subscription-banner__container-image" data-v-4c97ca31><div class="tp-image" style="border-radius:0;" data-v-d15050b5 data-v-4c97ca31><img class="tp-image__image" src="/images/tags-bell/tags-bell.png" srcset="undefined undefinedw,undefined undefinedw" sizes alt style="object-fit:fill;aspect-ratio:auto 1/1;object-position:50% 50%;" loading="auto" decoding="async" width="72" height="72" data-v-d15050b5></div></div><div class="tp-tag-subscription-banner__text-content" data-v-4c97ca31><span class="tp-tag-subscription-banner__title" data-v-4c97ca31>Следите за новыми постами по любимым темам </span><p class="tp-tag-subscription-banner__description" data-v-4c97ca31>Подпишитесь на интересующие вас теги, чтобы следить за новыми постами и быть в курсе событий.</p></div><button class="tp-tag-subscription-banner__close" data-v-4c97ca31><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" role="presentation" data-v-4c97ca31><!----><g fill="inherit" stroke="inherit"><!--[--><path fill-rule="evenodd" clip-rule="evenodd" d="m12 10.62 5.242-5.242a1 1 0 1 1 1.414 1.414l-5.242 5.243 5.242 5.243a1 1 0 0 1-1.414 1.414L12 13.449l-5.243 5.243a1 1 0 0 1-1.414-1.414l5.242-5.243-5.242-5.243a1 1 0 1 1 1.414-1.414L12 10.621Z" data-v-4c97ca31></path><!--]--></g></svg></button></div><div class="tp-post-page__tags" data-v-a1103d06><div class="tp-tags" data-v-a1103d06 data-v-97350194><!--[--><div class="tp-tag tp-tag--primary" data-v-18ee51fb data-v-97350194><span class="tp-tag__text" data-v-18ee51fb><!--[-->Для начинающих <!--]--></span><div class="tp-tag__additional-content" data-v-18ee51fb><!--[--><div class="tp-tooltip" data-v-f1909e3a data-v-97350194><!--[--><button class="tp-tags__tag-button" data-v-97350194><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 28 28" role="presentation" data-v-97350194><!----><g fill="inherit" stroke="var(--tp-color-text-tertiary)"><!--[--><!--[--><circle cx="14" cy="14" r="12" fill="transparent" stroke="inherit" stroke-linecap="round" stroke-width="2.667"></circle><path stroke="inherit" stroke-linecap="round" stroke-width="2.667" d="M8.464 14h11.072M14 8.464v11.072"></path><!--]--><!--]--></g></svg></button><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>Подписаться на тег</span></div><!--]--></div></div><div class="tp-tag tp-tag--primary" data-v-18ee51fb data-v-97350194><span class="tp-tag__text" data-v-18ee51fb><!--[-->Веб-разработка <!--]--></span><div class="tp-tag__additional-content" data-v-18ee51fb><!--[--><div class="tp-tooltip" data-v-f1909e3a data-v-97350194><!--[--><button class="tp-tags__tag-button" data-v-97350194><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 28 28" role="presentation" data-v-97350194><!----><g fill="inherit" stroke="var(--tp-color-text-tertiary)"><!--[--><!--[--><circle cx="14" cy="14" r="12" fill="transparent" stroke="inherit" stroke-linecap="round" stroke-width="2.667"></circle><path stroke="inherit" stroke-linecap="round" stroke-width="2.667" d="M8.464 14h11.072M14 8.464v11.072"></path><!--]--><!--]--></g></svg></button><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>Подписаться на тег</span></div><!--]--></div></div><div class="tp-tag tp-tag--primary" data-v-18ee51fb data-v-97350194><span class="tp-tag__text" data-v-18ee51fb><!--[-->Python <!--]--></span><div class="tp-tag__additional-content" data-v-18ee51fb><!--[--><div class="tp-tooltip" data-v-f1909e3a data-v-97350194><!--[--><button class="tp-tags__tag-button" data-v-97350194><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 28 28" role="presentation" data-v-97350194><!----><g fill="inherit" stroke="var(--tp-color-text-tertiary)"><!--[--><!--[--><circle cx="14" cy="14" r="12" fill="transparent" stroke="inherit" stroke-linecap="round" stroke-width="2.667"></circle><path stroke="inherit" stroke-linecap="round" stroke-width="2.667" d="M8.464 14h11.072M14 8.464v11.072"></path><!--]--><!--]--></g></svg></button><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>Подписаться на тег</span></div><!--]--></div></div><div class="tp-tag tp-tag--primary" data-v-18ee51fb data-v-97350194><span class="tp-tag__text" data-v-18ee51fb><!--[-->Django <!--]--></span><div class="tp-tag__additional-content" data-v-18ee51fb><!--[--><div class="tp-tooltip" data-v-f1909e3a data-v-97350194><!--[--><button class="tp-tags__tag-button" data-v-97350194><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 28 28" role="presentation" data-v-97350194><!----><g fill="inherit" stroke="var(--tp-color-text-tertiary)"><!--[--><!--[--><circle cx="14" cy="14" r="12" fill="transparent" stroke="inherit" stroke-linecap="round" stroke-width="2.667"></circle><path stroke="inherit" stroke-linecap="round" stroke-width="2.667" d="M8.464 14h11.072M14 8.464v11.072"></path><!--]--><!--]--></g></svg></button><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>Подписаться на тег</span></div><!--]--></div></div><div class="tp-tag tp-tag--primary" data-v-18ee51fb data-v-97350194><span class="tp-tag__text" data-v-18ee51fb><!--[-->React <!--]--></span><div class="tp-tag__additional-content" data-v-18ee51fb><!--[--><div class="tp-tooltip" data-v-f1909e3a data-v-97350194><!--[--><button class="tp-tags__tag-button" data-v-97350194><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 28 28" role="presentation" data-v-97350194><!----><g fill="inherit" stroke="var(--tp-color-text-tertiary)"><!--[--><!--[--><circle cx="14" cy="14" r="12" fill="transparent" stroke="inherit" stroke-linecap="round" stroke-width="2.667"></circle><path stroke="inherit" stroke-linecap="round" stroke-width="2.667" d="M8.464 14h11.072M14 8.464v11.072"></path><!--]--><!--]--></g></svg></button><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>Подписаться на тег</span></div><!--]--></div></div><!--]--></div></div></div><div class="tp-post-page__actions" data-v-a1103d06><div class="tp-post-page__actions-buttons" data-v-a1103d06><div class="tp-reactions" data-v-d6932f57 data-v-a1103d06><button class="tp-button-card" style="background-color:;border-color:;" aria-label="Открыть панель реакций" data-v-8bf6fb70 data-v-d6932f57><span class="tp-button-card__icon-box" data-v-8bf6fb70><!--[--><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" data-v-d6932f57><!----><g fill="var(--tp-color-text-tertiary)" stroke="none"><!--[--><path d="M7 20.9999V7.99993L13 2.04993C13.25 1.79993 13.5457 1.65393 13.887 1.61193C14.229 1.5706 14.5583 1.63326 14.875 1.79993C15.1917 1.9666 15.425 2.19993 15.575 2.49993C15.725 2.79993 15.7583 3.10826 15.675 3.42493L14.55 7.99993H21C21.5333 7.99993 22 8.19993 22.4 8.59993C22.8 8.99993 23 9.4666 23 9.99993V11.9999C23 12.1166 22.9833 12.2416 22.95 12.3749C22.9167 12.5083 22.8833 12.6333 22.85 12.7499L19.85 19.7999C19.7 20.1333 19.45 20.4166 19.1 20.6499C18.75 20.8833 18.3833 20.9999 18 20.9999H7ZM9 8.84993V18.9999H18L21 11.9999V9.99993H12L13.35 4.49993L9 8.84993ZM4 20.9999C3.45 20.9999 2.97933 20.8043 2.588 20.4129C2.196 20.0209 2 19.5499 2 18.9999V9.99993C2 9.44993 2.196 8.97893 2.588 8.58693C2.97933 8.1956 3.45 7.99993 4 7.99993H7V9.99993H4V18.9999H7V20.9999H4ZM9 18.9999V8.84993V18.9999Z" data-v-d6932f57></path><!--]--></g></svg><!--]--></span><span class="tp-button-card__text" data-v-8bf6fb70><!--[-->21<!--]--></span></button><!----></div><div class="tp-tooltip" data-v-f1909e3a data-v-a1103d06><!--[--><button class="tp-button-card" style="" data-v-8bf6fb70 data-v-a1103d06><span class="tp-button-card__icon-box" data-v-8bf6fb70><!--[--><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" data-v-a1103d06><!----><g fill="var(--tp-color-text-tertiary)" stroke="none"><!--[--><path d="m21.851 5.569-2.377-2.377a.978.978 0 0 0-1.38 0L12.637 8.65a.978.978 0 0 0-.283.695v2.367a.978.978 0 0 0 .978.978h2.367a.977.977 0 0 0 .695-.283l5.458-5.459a.979.979 0 0 0 0-1.38Zm-6.564 5.165h-.978v-.978l4.48-4.48.979.978-4.48 4.48ZM19.2 12.69a.978.978 0 0 0-.978.979 6.847 6.847 0 0 1-6.848 6.847H5.906l.626-.616a.978.978 0 0 0 0-1.39 6.848 6.848 0 0 1 4.842-11.689.978.978 0 0 0 0-1.956 8.804 8.804 0 0 0-6.847 14.301L2.854 20.8a.979.979 0 0 0-.205 1.066.979.979 0 0 0 .9.607h7.825a8.804 8.804 0 0 0 8.804-8.804.978.978 0 0 0-.978-.979Z" data-v-a1103d06></path><!--]--></g></svg><!--]--></span><span class="tp-button-card__text" data-v-8bf6fb70><!--[-->20<!--]--></span></button><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>Комментарии</span></div><div class="tp-tooltip" data-v-f1909e3a data-v-a1103d06><!--[--><button class="tp-button-card" style="" data-v-8bf6fb70 data-v-a1103d06><span class="tp-button-card__icon-box" data-v-8bf6fb70><!--[--><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" data-v-a1103d06><!----><g fill="var(--tp-color-text-tertiary)" stroke="none"><!--[--><path fill-rule="evenodd" clip-rule="evenodd" d="M9 4a1 1 0 0 0-1 1v14.259l5-2.917 5 2.917V5a1 1 0 0 0-1-1H9ZM6 5a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v15.826a1.1 1.1 0 0 1-1.654.95L13 18.658l-5.346 3.118A1.1 1.1 0 0 1 6 20.826V5Z" data-v-a1103d06></path><!--]--></g></svg><!--]--></span><span class="tp-button-card__text" data-v-8bf6fb70><!--[-->74<!--]--></span></button><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>В закладки</span></div><div class="tp-share" data-v-a1103d06 data-v-8b417359><button class="tp-share-button" data-v-8b417359 data-v-12935963><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" data-v-12935963><!----><g fill="inherit" stroke="none"><!--[--><path d="M18.898 15.696a3.24 3.24 0 0 0-2.64 1.369l-6.837-3.11a3.24 3.24 0 0 0 .21-1.045 3.352 3.352 0 0 0-.08-.705l5.88-4.212a3.24 3.24 0 1 0-.81-2.146c.002.237.029.473.08.704l-5.88 4.212a3.24 3.24 0 1 0-2.43 5.387 3.24 3.24 0 0 0 2.155-.81l7.112 3.272v.324a3.24 3.24 0 1 0 3.24-3.24ZM17.86 4.226a1.62 1.62 0 1 1 0 3.24 1.62 1.62 0 0 1 0-3.24ZM6.39 14.53a1.62 1.62 0 1 1 0-3.24 1.62 1.62 0 0 1 0 3.24Zm12.507 6.026a1.62 1.62 0 1 1 0-3.24 1.62 1.62 0 0 1 0 3.24Z" data-v-12935963></path><!--]--></g></svg><!--[--><!--]--></button><!----></div></div><!----><span class="tp-chip" data-v-59e87408 data-v-a1103d06><span class="tp-chip__icon-box" data-v-59e87408><!--[--><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" data-v-a1103d06><!----><g fill="transparent" stroke="var(--tp-color-text-tertiary)"><!--[--><!--[--><g clip-path="url(#tp-icon-eye-a)"><g clip-path="url(#tp-icon-eye-b)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5.501 11.762s2.363-4.727 6.5-4.727c4.135 0 6.499 4.727 6.499 4.727s-2.364 4.726-6.5 4.726-6.499-4.726-6.499-4.726Z"></path><path d="M12 13.534a1.773 1.773 0 1 0 0-3.545 1.773 1.773 0 0 0 0 3.545Z"></path></g></g><defs><clipPath id="tp-icon-eye-a"><path fill="#fff" transform="translate(0 .035)" d="M0 0h24v24H0z"></path></clipPath><clipPath id="tp-icon-eye-b"><path fill="#fff" transform="translate(4.5 4.535)" d="M0 0h15v15H0z"></path></clipPath></defs><!--]--><!--]--></g></svg><!--]--></span><span class="tp-chip__text" data-v-59e87408><!--[--> 91770<!--]--></span></span></div></div><div class="tp-post-page__container-listok-end-content" data-v-a1103d06><span data-v-a1103d06></span></div><div class="tp-post-page__container-comments" data-v-a1103d06><div id="tproger-comments" class="tp-comments" data-v-a1103d06 data-v-8fb6c9e4><div class="tp-comments__title" data-v-8fb6c9e4>Что думаете?</div><div class="tp-comments-input" data-v-8fb6c9e4 data-v-9fc13c82><!----><div class="tp-avatar tp-avatar--own tp-avatar--circle tp-comments-input__action-avatar" style="width:48px;height:48px;" data-v-6e456a49 data-v-9fc13c82><img class="tp-avatar__image tp-avatar__image--cover" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9Ijk2IiBoZWlnaHQ9Ijk2IiByeD0iMTgiIGZpbGw9IiNGNUVFRTUiLz4KPGc+CjxwYXRoIGQ9Ik0zNy4wNjQ5IDY0LjQ4MjJWNTAuMzQ1TDUwLjM3MDUgNDQuNTIzOFYxMDUuMjMxSC01LjUzNzQxQy04LjMwOTQxIDEwMC4yNDEgLTIuNzA5OTUgODguNTk4NiA1LjI3MzQyIDgxLjk0NThDMTEuMDc4IDc4LjQ2MTQgMzcuMDY0OSA2OC42NDAyIDM3LjA2NDkgNjQuNDgyMloiIGZpbGw9IiNFNkMxOUMiLz4KPHBhdGggZD0iTTU4LjY4NyA2NC40ODIyQzU3LjI2ODkgNjEuNDczMiA1OC42ODcgNTMuNjcxNCA1OC42ODcgNTAuMzQ1TDQ1LjM4MTQgNDQuNTIzOFYxMDUuMjMxTDEwMC4zNTEgMTAzLjU5MkMxMDMuMTIzIDk4LjYwMjggMTAwLjM1MSA4Ni43NjkxIDg5LjU0MDIgODAuMzA3NkM4MC4zMDk0IDc3LjUzODMgNjAuOTI0OCA2OS4yMzA2IDU4LjY4NyA2NC40ODIyWiIgZmlsbD0iI0U2QzE5QyIvPgo8cGF0aCBkPSJNNTguNjg2MSA2NS4zMTRDNDkuMzcyMSA3MS45NjY4IDQwLjM5MDkgNjguMDg2IDM3LjA2NDUgNjUuMzE0VjU2LjE2NjRMNTguNjg2MSA1MS4xNzY4VjY1LjMxNFoiIGZpbGw9IiNENUIxOEQiLz4KPHBhdGggZD0iTTI3LjkzNDEgMzMuNjQ1MUMyNy4wMjkgMjIuNDgyMSAzNS44NDQyIDEyLjkyMzEgNDcuMDQzOSAxMi45MjMxVjEyLjkyMzFDNTguMjQzNiAxMi45MjMxIDY3LjA1ODkgMjIuNDgyMSA2Ni4xNTM4IDMzLjY0NTFMNjUuNTQ3MiA0MS4xMjY4QzY1LjQwODggNDIuODMzIDY1LjEwMjkgNDQuNTIxNSA2NC42MzM5IDQ2LjE2NzhMNjIuMDkxMyA1NS4wOTI0QzYwLjIyNzYgNjEuNjMzOCA1NC4yNTEgNjYuMTQ1NSA0Ny40NDkyIDY2LjE0NTVWNjYuMTQ1NUM0MC45OTU5IDY2LjE0NTUgMzUuMjQzNiA2Mi4wNzcgMzMuMDk0IDU1Ljk5MjJMMjkuODUgNDYuODA5OEMyOS4xMTg5IDQ0Ljc0MDIgMjguNjU4OSA0Mi41ODQ2IDI4LjQ4MTUgNDAuMzk2OEwyNy45MzQxIDMzLjY0NTFaIiBmaWxsPSIjRjJDRUE1Ii8+CjwvZz4KPC9zdmc+Cg==" alt data-v-6e456a49></div><div class="tp-textarea tp-textarea--primary tp-textarea--elastic tp-textarea--actions-right tp-textarea--actions tp-comments-input__textarea" data-v-14c4c8fc data-v-9fc13c82><label class="tp-textarea__label tp-textarea__label--extra-small" data-v-14c4c8fc> <span class="tp-textarea__textarea-container" data-v-14c4c8fc><textarea cols="20" maxlength="none" minlength="none" placeholder="Комментировать..." rows="1" class="tp-textarea__textarea" data-v-14c4c8fc></textarea><span class="tp-textarea__actions" data-v-14c4c8fc><!--[--><div class="tp-comments-input__actions" data-v-9fc13c82><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" class="tp-comments-input__actions-icon" data-v-9fc13c82><!----><g fill="inherit" stroke="none"><!--[--><path fill-rule="evenodd" clip-rule="evenodd" d="M3.31775 19.6578C3.31775 20.3006 3.99052 20.7215 4.56856 20.4405L20.5102 12.6899C21.1632 12.3724 21.1632 11.442 20.5102 11.1245L4.56856 3.37385C3.99052 3.09281 3.31775 3.51379 3.31775 4.15653L3.31775 9.79016C3.31775 10.2344 3.65235 10.6073 4.09399 10.6553L11.1265 11.4197C11.3752 11.4468 11.5637 11.6569 11.5637 11.9071C11.5637 12.1573 11.3752 12.3674 11.1265 12.3944L4.09399 13.1588C3.65235 13.2068 3.31775 13.5798 3.31775 14.024L3.31775 19.6578Z" fill-color="inherit" data-v-9fc13c82></path><!--]--></g></svg></div><!--]--></span></span></label></div></div><div class="tp-comments__container" data-v-8fb6c9e4><div class="tp-comments__actions" data-v-8fb6c9e4><div class="tp-comments__count" data-v-8fb6c9e4>20 комментариев</div><div class="tp-comments-filter" data-v-8fb6c9e4 data-v-6f113051><div class="tp-comments-filter__current" data-v-6f113051>Сначала интересные <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" fill="none" class="tp-comments-filter__current-icon" data-v-6f113051><!----><g fill="inherit" stroke="inherit"><!--[--><path d="M9 11L12.5 14L16 11" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-6f113051></path><!--]--></g></svg></div><!----></div></div><div class="tp-comments__box" data-v-8fb6c9e4><div class="tp-comments-list" data-v-8fb6c9e4 data-v-30007e44><!--[--><div id="tproger-comments-5993" class="tp-comments-item" data-v-30007e44 data-v-63130dc8><div class="tp-comments-item__avatar" data-v-63130dc8><div class="tp-avatar tp-avatar--medium tp-avatar--circle" style="width:48px;height:48px;" radius="50%" data-v-6e456a49 data-v-63130dc8><img class="tp-avatar__image tp-avatar__image--cover" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9Ijk2IiBoZWlnaHQ9Ijk2IiByeD0iMTgiIGZpbGw9IiNGNUVFRTUiLz4KPGc+CjxwYXRoIGQ9Ik0zNy4wNjQ5IDY0LjQ4MjJWNTAuMzQ1TDUwLjM3MDUgNDQuNTIzOFYxMDUuMjMxSC01LjUzNzQxQy04LjMwOTQxIDEwMC4yNDEgLTIuNzA5OTUgODguNTk4NiA1LjI3MzQyIDgxLjk0NThDMTEuMDc4IDc4LjQ2MTQgMzcuMDY0OSA2OC42NDAyIDM3LjA2NDkgNjQuNDgyMloiIGZpbGw9IiNFNkMxOUMiLz4KPHBhdGggZD0iTTU4LjY4NyA2NC40ODIyQzU3LjI2ODkgNjEuNDczMiA1OC42ODcgNTMuNjcxNCA1OC42ODcgNTAuMzQ1TDQ1LjM4MTQgNDQuNTIzOFYxMDUuMjMxTDEwMC4zNTEgMTAzLjU5MkMxMDMuMTIzIDk4LjYwMjggMTAwLjM1MSA4Ni43NjkxIDg5LjU0MDIgODAuMzA3NkM4MC4zMDk0IDc3LjUzODMgNjAuOTI0OCA2OS4yMzA2IDU4LjY4NyA2NC40ODIyWiIgZmlsbD0iI0U2QzE5QyIvPgo8cGF0aCBkPSJNNTguNjg2MSA2NS4zMTRDNDkuMzcyMSA3MS45NjY4IDQwLjM5MDkgNjguMDg2IDM3LjA2NDUgNjUuMzE0VjU2LjE2NjRMNTguNjg2MSA1MS4xNzY4VjY1LjMxNFoiIGZpbGw9IiNENUIxOEQiLz4KPHBhdGggZD0iTTI3LjkzNDEgMzMuNjQ1MUMyNy4wMjkgMjIuNDgyMSAzNS44NDQyIDEyLjkyMzEgNDcuMDQzOSAxMi45MjMxVjEyLjkyMzFDNTguMjQzNiAxMi45MjMxIDY3LjA1ODkgMjIuNDgyMSA2Ni4xNTM4IDMzLjY0NTFMNjUuNTQ3MiA0MS4xMjY4QzY1LjQwODggNDIuODMzIDY1LjEwMjkgNDQuNTIxNSA2NC42MzM5IDQ2LjE2NzhMNjIuMDkxMyA1NS4wOTI0QzYwLjIyNzYgNjEuNjMzOCA1NC4yNTEgNjYuMTQ1NSA0Ny40NDkyIDY2LjE0NTVWNjYuMTQ1NUM0MC45OTU5IDY2LjE0NTUgMzUuMjQzNiA2Mi4wNzcgMzMuMDk0IDU1Ljk5MjJMMjkuODUgNDYuODA5OEMyOS4xMTg5IDQ0Ljc0MDIgMjguNjU4OSA0Mi41ODQ2IDI4LjQ4MTUgNDAuMzk2OEwyNy45MzQxIDMzLjY0NTFaIiBmaWxsPSIjRjJDRUE1Ii8+CjwvZz4KPC9zdmc+Cg==" alt="Аватар" data-v-6e456a49></div></div><div class="tp-comments-item__content" data-v-63130dc8><div class="tp-comments__header" data-v-63130dc8 data-v-b0fb54f3><div class="tp-comments__header-left" data-v-b0fb54f3><div class="tp-comments__author-name" data-v-b0fb54f3><a href="/author/42557" class="tp-comments__author-link" data-v-b0fb54f3>Alex undefined</a></div><div class="tp-comments__date" data-v-b0fb54f3><div class="tp-date tp-date--styled" date-type="fromISO" data-v-e8bf1fd6 data-v-b0fb54f3><div class="tp-tooltip" data-v-f1909e3a data-v-e8bf1fd6><!--[--><time datetime="2022-01-06T05:26:50+00:00" class="tp-date__time" data-v-e8bf1fd6>06 янв 2022</time><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>06 янв 2022 в 05:26</span></div></div></div><!----><!----><!----></div><div class="tp-comments__header-right" data-v-b0fb54f3><!--[--><div style="display:none;" class="tp-comments-item__header-actions" data-v-63130dc8><!----><!----><!----></div><!--]--></div><!----></div><div class="tp-comments-item__body" data-v-63130dc8><!----><span data-v-63130dc8>В части про настройку Bable тоже нет важного для новичков куска текста." "presets": [  ... " - Нужно класть в файл конфигураций babel, который не создается автоматически, а его нужно создать в этой же директории с названием .babelrc самостоятельно и туда этот код положить. Фрагмент оригинала статьи {    Now configure babel with a .babelrc (still inside ./frontend):}</span><!----></div><div class="tp-comments-item__footer" data-v-63130dc8><button class="tp-comments-item__reply" data-v-63130dc8> Ответить </button><div class="tp-comments-votes" data-v-63130dc8 data-v-12d4d73c><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M7 20.9999V7.99993L13 2.04993C13.25 1.79993 13.5457 1.65393 13.887 1.61193C14.229 1.5706 14.5583 1.63326 14.875 1.79993C15.1917 1.9666 15.425 2.19993 15.575 2.49993C15.725 2.79993 15.7583 3.10826 15.675 3.42493L14.55 7.99993H21C21.5333 7.99993 22 8.19993 22.4 8.59993C22.8 8.99993 23 9.4666 23 9.99993V11.9999C23 12.1166 22.9833 12.2416 22.95 12.3749C22.9167 12.5083 22.8833 12.6333 22.85 12.7499L19.85 19.7999C19.7 20.1333 19.45 20.4166 19.1 20.6499C18.75 20.8833 18.3833 20.9999 18 20.9999H7ZM9 8.84993V18.9999H18L21 11.9999V9.99993H12L13.35 4.49993L9 8.84993ZM4 20.9999C3.45 20.9999 2.97933 20.8043 2.588 20.4129C2.196 20.0209 2 19.5499 2 18.9999V9.99993C2 9.44993 2.196 8.97893 2.588 8.58693C2.97933 8.1956 3.45 7.99993 4 7.99993H7V9.99993H4V18.9999H7V20.9999H4ZM9 18.9999V8.84993V18.9999Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>5</div></div><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M17 3.00007L17 16.0001L11 21.9501C10.75 22.2001 10.4543 22.3461 10.113 22.3881C9.771 22.4294 9.44167 22.3667 9.125 22.2001C8.80833 22.0334 8.575 21.8001 8.425 21.5001C8.275 21.2001 8.24167 20.8917 8.325 20.5751L9.45 16.0001L3 16.0001C2.46667 16.0001 2 15.8001 1.6 15.4001C1.2 15.0001 1 14.5334 1 14.0001L1 12.0001C1 11.8834 1.01667 11.7584 1.05 11.6251C1.08333 11.4917 1.11667 11.3667 1.15 11.2501L4.15 4.20007C4.3 3.86674 4.55 3.5834 4.9 3.35007C5.25 3.11674 5.61667 3.00007 6 3.00007L17 3.00007ZM15 15.1501L15 5.00007L6 5.00007L3 12.0001L3 14.0001L12 14.0001L10.65 19.5001L15 15.1501ZM20 3.00007C20.55 3.00007 21.0207 3.19574 21.412 3.58707C21.804 3.97907 22 4.45007 22 5.00007L22 14.0001C22 14.5501 21.804 15.0211 21.412 15.4131C21.0207 15.8044 20.55 16.0001 20 16.0001L17 16.0001L17 14.0001L20 14.0001L20 5.00007L17 5.00007L17 3.00007L20 3.00007ZM15 5.00007L15 15.1501L15 5.00007Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>0</div></div></div></div><div style="display:none;" class="tp-comments-item__answer" data-v-63130dc8><div class="tp-comments-input" data-v-63130dc8 data-v-9fc13c82><!----><div class="tp-avatar tp-avatar--own tp-avatar--circle tp-comments-input__action-avatar" style="width:48px;height:48px;" data-v-6e456a49 data-v-9fc13c82><img class="tp-avatar__image tp-avatar__image--cover" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9Ijk2IiBoZWlnaHQ9Ijk2IiByeD0iMTgiIGZpbGw9IiNGNUVFRTUiLz4KPGc+CjxwYXRoIGQ9Ik0zNy4wNjQ5IDY0LjQ4MjJWNTAuMzQ1TDUwLjM3MDUgNDQuNTIzOFYxMDUuMjMxSC01LjUzNzQxQy04LjMwOTQxIDEwMC4yNDEgLTIuNzA5OTUgODguNTk4NiA1LjI3MzQyIDgxLjk0NThDMTEuMDc4IDc4LjQ2MTQgMzcuMDY0OSA2OC42NDAyIDM3LjA2NDkgNjQuNDgyMloiIGZpbGw9IiNFNkMxOUMiLz4KPHBhdGggZD0iTTU4LjY4NyA2NC40ODIyQzU3LjI2ODkgNjEuNDczMiA1OC42ODcgNTMuNjcxNCA1OC42ODcgNTAuMzQ1TDQ1LjM4MTQgNDQuNTIzOFYxMDUuMjMxTDEwMC4zNTEgMTAzLjU5MkMxMDMuMTIzIDk4LjYwMjggMTAwLjM1MSA4Ni43NjkxIDg5LjU0MDIgODAuMzA3NkM4MC4zMDk0IDc3LjUzODMgNjAuOTI0OCA2OS4yMzA2IDU4LjY4NyA2NC40ODIyWiIgZmlsbD0iI0U2QzE5QyIvPgo8cGF0aCBkPSJNNTguNjg2MSA2NS4zMTRDNDkuMzcyMSA3MS45NjY4IDQwLjM5MDkgNjguMDg2IDM3LjA2NDUgNjUuMzE0VjU2LjE2NjRMNTguNjg2MSA1MS4xNzY4VjY1LjMxNFoiIGZpbGw9IiNENUIxOEQiLz4KPHBhdGggZD0iTTI3LjkzNDEgMzMuNjQ1MUMyNy4wMjkgMjIuNDgyMSAzNS44NDQyIDEyLjkyMzEgNDcuMDQzOSAxMi45MjMxVjEyLjkyMzFDNTguMjQzNiAxMi45MjMxIDY3LjA1ODkgMjIuNDgyMSA2Ni4xNTM4IDMzLjY0NTFMNjUuNTQ3MiA0MS4xMjY4QzY1LjQwODggNDIuODMzIDY1LjEwMjkgNDQuNTIxNSA2NC42MzM5IDQ2LjE2NzhMNjIuMDkxMyA1NS4wOTI0QzYwLjIyNzYgNjEuNjMzOCA1NC4yNTEgNjYuMTQ1NSA0Ny40NDkyIDY2LjE0NTVWNjYuMTQ1NUM0MC45OTU5IDY2LjE0NTUgMzUuMjQzNiA2Mi4wNzcgMzMuMDk0IDU1Ljk5MjJMMjkuODUgNDYuODA5OEMyOS4xMTg5IDQ0Ljc0MDIgMjguNjU4OSA0Mi41ODQ2IDI4LjQ4MTUgNDAuMzk2OEwyNy45MzQxIDMzLjY0NTFaIiBmaWxsPSIjRjJDRUE1Ii8+CjwvZz4KPC9zdmc+Cg==" alt data-v-6e456a49></div><div class="tp-textarea tp-textarea--primary tp-textarea--elastic tp-textarea--actions-right tp-textarea--actions tp-comments-input__textarea" data-v-14c4c8fc data-v-9fc13c82><label class="tp-textarea__label tp-textarea__label--extra-small" data-v-14c4c8fc> <span class="tp-textarea__textarea-container" data-v-14c4c8fc><textarea cols="20" maxlength="none" minlength="none" placeholder="Комментировать..." rows="1" class="tp-textarea__textarea" data-v-14c4c8fc></textarea><span class="tp-textarea__actions" data-v-14c4c8fc><!--[--><div class="tp-comments-input__actions" data-v-9fc13c82><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" class="tp-comments-input__actions-icon" data-v-9fc13c82><!----><g fill="inherit" stroke="none"><!--[--><path fill-rule="evenodd" clip-rule="evenodd" d="M3.31775 19.6578C3.31775 20.3006 3.99052 20.7215 4.56856 20.4405L20.5102 12.6899C21.1632 12.3724 21.1632 11.442 20.5102 11.1245L4.56856 3.37385C3.99052 3.09281 3.31775 3.51379 3.31775 4.15653L3.31775 9.79016C3.31775 10.2344 3.65235 10.6073 4.09399 10.6553L11.1265 11.4197C11.3752 11.4468 11.5637 11.6569 11.5637 11.9071C11.5637 12.1573 11.3752 12.3674 11.1265 12.3944L4.09399 13.1588C3.65235 13.2068 3.31775 13.5798 3.31775 14.024L3.31775 19.6578Z" fill-color="inherit" data-v-9fc13c82></path><!--]--></g></svg></div><!--]--></span></span></label></div></div></div><!----></div><!----></div><div id="tproger-comments-2067" class="tp-comments-item" data-v-30007e44 data-v-63130dc8><div class="tp-comments-item__avatar" data-v-63130dc8><div class="tp-avatar tp-avatar--medium tp-avatar--circle" style="width:48px;height:48px;" radius="50%" data-v-6e456a49 data-v-63130dc8><img class="tp-avatar__image tp-avatar__image--cover" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9Ijk2IiBoZWlnaHQ9Ijk2IiByeD0iMTgiIGZpbGw9IiNGNUVFRTUiLz4KPGc+CjxwYXRoIGQ9Ik0zNy4wNjQ5IDY0LjQ4MjJWNTAuMzQ1TDUwLjM3MDUgNDQuNTIzOFYxMDUuMjMxSC01LjUzNzQxQy04LjMwOTQxIDEwMC4yNDEgLTIuNzA5OTUgODguNTk4NiA1LjI3MzQyIDgxLjk0NThDMTEuMDc4IDc4LjQ2MTQgMzcuMDY0OSA2OC42NDAyIDM3LjA2NDkgNjQuNDgyMloiIGZpbGw9IiNFNkMxOUMiLz4KPHBhdGggZD0iTTU4LjY4NyA2NC40ODIyQzU3LjI2ODkgNjEuNDczMiA1OC42ODcgNTMuNjcxNCA1OC42ODcgNTAuMzQ1TDQ1LjM4MTQgNDQuNTIzOFYxMDUuMjMxTDEwMC4zNTEgMTAzLjU5MkMxMDMuMTIzIDk4LjYwMjggMTAwLjM1MSA4Ni43NjkxIDg5LjU0MDIgODAuMzA3NkM4MC4zMDk0IDc3LjUzODMgNjAuOTI0OCA2OS4yMzA2IDU4LjY4NyA2NC40ODIyWiIgZmlsbD0iI0U2QzE5QyIvPgo8cGF0aCBkPSJNNTguNjg2MSA2NS4zMTRDNDkuMzcyMSA3MS45NjY4IDQwLjM5MDkgNjguMDg2IDM3LjA2NDUgNjUuMzE0VjU2LjE2NjRMNTguNjg2MSA1MS4xNzY4VjY1LjMxNFoiIGZpbGw9IiNENUIxOEQiLz4KPHBhdGggZD0iTTI3LjkzNDEgMzMuNjQ1MUMyNy4wMjkgMjIuNDgyMSAzNS44NDQyIDEyLjkyMzEgNDcuMDQzOSAxMi45MjMxVjEyLjkyMzFDNTguMjQzNiAxMi45MjMxIDY3LjA1ODkgMjIuNDgyMSA2Ni4xNTM4IDMzLjY0NTFMNjUuNTQ3MiA0MS4xMjY4QzY1LjQwODggNDIuODMzIDY1LjEwMjkgNDQuNTIxNSA2NC42MzM5IDQ2LjE2NzhMNjIuMDkxMyA1NS4wOTI0QzYwLjIyNzYgNjEuNjMzOCA1NC4yNTEgNjYuMTQ1NSA0Ny40NDkyIDY2LjE0NTVWNjYuMTQ1NUM0MC45OTU5IDY2LjE0NTUgMzUuMjQzNiA2Mi4wNzcgMzMuMDk0IDU1Ljk5MjJMMjkuODUgNDYuODA5OEMyOS4xMTg5IDQ0Ljc0MDIgMjguNjU4OSA0Mi41ODQ2IDI4LjQ4MTUgNDAuMzk2OEwyNy45MzQxIDMzLjY0NTFaIiBmaWxsPSIjRjJDRUE1Ii8+CjwvZz4KPC9zdmc+Cg==" alt="Аватар" data-v-6e456a49></div></div><div class="tp-comments-item__content" data-v-63130dc8><div class="tp-comments__header" data-v-63130dc8 data-v-b0fb54f3><div class="tp-comments__header-left" data-v-b0fb54f3><div class="tp-comments__author-name" data-v-b0fb54f3><a href="/author/25748" class="tp-comments__author-link" data-v-b0fb54f3>HarleyK1ng</a></div><div class="tp-comments__date" data-v-b0fb54f3><div class="tp-date tp-date--styled" date-type="fromISO" data-v-e8bf1fd6 data-v-b0fb54f3><div class="tp-tooltip" data-v-f1909e3a data-v-e8bf1fd6><!--[--><time datetime="2021-04-01T20:29:50+00:00" class="tp-date__time" data-v-e8bf1fd6>01 апр 2021</time><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>01 апр 2021 в 20:29</span></div></div></div><!----><!----><!----></div><div class="tp-comments__header-right" data-v-b0fb54f3><!--[--><div style="display:none;" class="tp-comments-item__header-actions" data-v-63130dc8><!----><!----><!----></div><!--]--></div><!----></div><div class="tp-comments-item__body" data-v-63130dc8><!----><span data-v-63130dc8>Вот это не будет работать:
"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"
}


Вместо этого пишите так:
"scripts": {
    "dev": "webpack --mode development ./src/index.js --output-path ./static/frontend/",
    "build": "webpack --mode production ./src/index.js --output-path ./static/frontend/"
  }


--output устарел и вместо него используется --output-path</span><!----></div><div class="tp-comments-item__footer" data-v-63130dc8><button class="tp-comments-item__reply" data-v-63130dc8> Ответить </button><div class="tp-comments-votes" data-v-63130dc8 data-v-12d4d73c><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M7 20.9999V7.99993L13 2.04993C13.25 1.79993 13.5457 1.65393 13.887 1.61193C14.229 1.5706 14.5583 1.63326 14.875 1.79993C15.1917 1.9666 15.425 2.19993 15.575 2.49993C15.725 2.79993 15.7583 3.10826 15.675 3.42493L14.55 7.99993H21C21.5333 7.99993 22 8.19993 22.4 8.59993C22.8 8.99993 23 9.4666 23 9.99993V11.9999C23 12.1166 22.9833 12.2416 22.95 12.3749C22.9167 12.5083 22.8833 12.6333 22.85 12.7499L19.85 19.7999C19.7 20.1333 19.45 20.4166 19.1 20.6499C18.75 20.8833 18.3833 20.9999 18 20.9999H7ZM9 8.84993V18.9999H18L21 11.9999V9.99993H12L13.35 4.49993L9 8.84993ZM4 20.9999C3.45 20.9999 2.97933 20.8043 2.588 20.4129C2.196 20.0209 2 19.5499 2 18.9999V9.99993C2 9.44993 2.196 8.97893 2.588 8.58693C2.97933 8.1956 3.45 7.99993 4 7.99993H7V9.99993H4V18.9999H7V20.9999H4ZM9 18.9999V8.84993V18.9999Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>4</div></div><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M17 3.00007L17 16.0001L11 21.9501C10.75 22.2001 10.4543 22.3461 10.113 22.3881C9.771 22.4294 9.44167 22.3667 9.125 22.2001C8.80833 22.0334 8.575 21.8001 8.425 21.5001C8.275 21.2001 8.24167 20.8917 8.325 20.5751L9.45 16.0001L3 16.0001C2.46667 16.0001 2 15.8001 1.6 15.4001C1.2 15.0001 1 14.5334 1 14.0001L1 12.0001C1 11.8834 1.01667 11.7584 1.05 11.6251C1.08333 11.4917 1.11667 11.3667 1.15 11.2501L4.15 4.20007C4.3 3.86674 4.55 3.5834 4.9 3.35007C5.25 3.11674 5.61667 3.00007 6 3.00007L17 3.00007ZM15 15.1501L15 5.00007L6 5.00007L3 12.0001L3 14.0001L12 14.0001L10.65 19.5001L15 15.1501ZM20 3.00007C20.55 3.00007 21.0207 3.19574 21.412 3.58707C21.804 3.97907 22 4.45007 22 5.00007L22 14.0001C22 14.5501 21.804 15.0211 21.412 15.4131C21.0207 15.8044 20.55 16.0001 20 16.0001L17 16.0001L17 14.0001L20 14.0001L20 5.00007L17 5.00007L17 3.00007L20 3.00007ZM15 5.00007L15 15.1501L15 5.00007Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>1</div></div></div></div><div style="display:none;" class="tp-comments-item__answer" data-v-63130dc8><div class="tp-comments-input" data-v-63130dc8 data-v-9fc13c82><!----><div class="tp-avatar tp-avatar--own tp-avatar--circle tp-comments-input__action-avatar" style="width:48px;height:48px;" data-v-6e456a49 data-v-9fc13c82><img class="tp-avatar__image tp-avatar__image--cover" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9Ijk2IiBoZWlnaHQ9Ijk2IiByeD0iMTgiIGZpbGw9IiNGNUVFRTUiLz4KPGc+CjxwYXRoIGQ9Ik0zNy4wNjQ5IDY0LjQ4MjJWNTAuMzQ1TDUwLjM3MDUgNDQuNTIzOFYxMDUuMjMxSC01LjUzNzQxQy04LjMwOTQxIDEwMC4yNDEgLTIuNzA5OTUgODguNTk4NiA1LjI3MzQyIDgxLjk0NThDMTEuMDc4IDc4LjQ2MTQgMzcuMDY0OSA2OC42NDAyIDM3LjA2NDkgNjQuNDgyMloiIGZpbGw9IiNFNkMxOUMiLz4KPHBhdGggZD0iTTU4LjY4NyA2NC40ODIyQzU3LjI2ODkgNjEuNDczMiA1OC42ODcgNTMuNjcxNCA1OC42ODcgNTAuMzQ1TDQ1LjM4MTQgNDQuNTIzOFYxMDUuMjMxTDEwMC4zNTEgMTAzLjU5MkMxMDMuMTIzIDk4LjYwMjggMTAwLjM1MSA4Ni43NjkxIDg5LjU0MDIgODAuMzA3NkM4MC4zMDk0IDc3LjUzODMgNjAuOTI0OCA2OS4yMzA2IDU4LjY4NyA2NC40ODIyWiIgZmlsbD0iI0U2QzE5QyIvPgo8cGF0aCBkPSJNNTguNjg2MSA2NS4zMTRDNDkuMzcyMSA3MS45NjY4IDQwLjM5MDkgNjguMDg2IDM3LjA2NDUgNjUuMzE0VjU2LjE2NjRMNTguNjg2MSA1MS4xNzY4VjY1LjMxNFoiIGZpbGw9IiNENUIxOEQiLz4KPHBhdGggZD0iTTI3LjkzNDEgMzMuNjQ1MUMyNy4wMjkgMjIuNDgyMSAzNS44NDQyIDEyLjkyMzEgNDcuMDQzOSAxMi45MjMxVjEyLjkyMzFDNTguMjQzNiAxMi45MjMxIDY3LjA1ODkgMjIuNDgyMSA2Ni4xNTM4IDMzLjY0NTFMNjUuNTQ3MiA0MS4xMjY4QzY1LjQwODggNDIuODMzIDY1LjEwMjkgNDQuNTIxNSA2NC42MzM5IDQ2LjE2NzhMNjIuMDkxMyA1NS4wOTI0QzYwLjIyNzYgNjEuNjMzOCA1NC4yNTEgNjYuMTQ1NSA0Ny40NDkyIDY2LjE0NTVWNjYuMTQ1NUM0MC45OTU5IDY2LjE0NTUgMzUuMjQzNiA2Mi4wNzcgMzMuMDk0IDU1Ljk5MjJMMjkuODUgNDYuODA5OEMyOS4xMTg5IDQ0Ljc0MDIgMjguNjU4OSA0Mi41ODQ2IDI4LjQ4MTUgNDAuMzk2OEwyNy45MzQxIDMzLjY0NTFaIiBmaWxsPSIjRjJDRUE1Ii8+CjwvZz4KPC9zdmc+Cg==" alt data-v-6e456a49></div><div class="tp-textarea tp-textarea--primary tp-textarea--elastic tp-textarea--actions-right tp-textarea--actions tp-comments-input__textarea" data-v-14c4c8fc data-v-9fc13c82><label class="tp-textarea__label tp-textarea__label--extra-small" data-v-14c4c8fc> <span class="tp-textarea__textarea-container" data-v-14c4c8fc><textarea cols="20" maxlength="none" minlength="none" placeholder="Комментировать..." rows="1" class="tp-textarea__textarea" data-v-14c4c8fc></textarea><span class="tp-textarea__actions" data-v-14c4c8fc><!--[--><div class="tp-comments-input__actions" data-v-9fc13c82><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" class="tp-comments-input__actions-icon" data-v-9fc13c82><!----><g fill="inherit" stroke="none"><!--[--><path fill-rule="evenodd" clip-rule="evenodd" d="M3.31775 19.6578C3.31775 20.3006 3.99052 20.7215 4.56856 20.4405L20.5102 12.6899C21.1632 12.3724 21.1632 11.442 20.5102 11.1245L4.56856 3.37385C3.99052 3.09281 3.31775 3.51379 3.31775 4.15653L3.31775 9.79016C3.31775 10.2344 3.65235 10.6073 4.09399 10.6553L11.1265 11.4197C11.3752 11.4468 11.5637 11.6569 11.5637 11.9071C11.5637 12.1573 11.3752 12.3674 11.1265 12.3944L4.09399 13.1588C3.65235 13.2068 3.31775 13.5798 3.31775 14.024L3.31775 19.6578Z" fill-color="inherit" data-v-9fc13c82></path><!--]--></g></svg></div><!--]--></span></span></label></div></div></div><div class="tp-comments-item__children" data-v-63130dc8><!--[--><div id="tproger-comments-6393" class="tp-comments-item" data-v-63130dc8 data-v-63130dc8><div class="tp-comments-item__avatar" data-v-63130dc8><div class="tp-avatar tp-avatar--medium tp-avatar--circle" style="width:40px;height:40px;" actual-width="48" actual-height="48" radius="50%" data-v-6e456a49 data-v-63130dc8><img class="tp-avatar__image tp-avatar__image--cover" src="https://lh3.googleusercontent.com/a/AATXAJwhLUsrPnB7IueWRHe7ZS_uNNZncLlWeHPN-6vU=s96-c" alt="Аватар пользователя Григорий Гуляев" loading="lazy" decoding="async" srcset="https://tproger.ru/signed_image/8KGdVkpUVOEOmxqa1fKuGsdw4_Z5IFSS2Vt6xLGaNz4/rs:fill:48:48:true/cb:vimg_1/f:webp/aHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd2hMVXNyUG5CN0l1ZVdSSGU3WlNfdU5OWm5jTGxXZUhQTi02dlU9czk2LWM 48w,https://tproger.ru/signed_image/KxUIwBDSEMdCM4EhslCsaoH3xP7IIQk3fCtMhblzWoE/rs:fill:96:96:true/cb:vimg_1/f:webp/aHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd2hMVXNyUG5CN0l1ZVdSSGU3WlNfdU5OWm5jTGxXZUhQTi02dlU9czk2LWM 96w" sizes="(min-width: 0px) 48px" data-v-6e456a49></div></div><div class="tp-comments-item__content" data-v-63130dc8><div class="tp-comments__header" data-v-63130dc8 data-v-b0fb54f3><div class="tp-comments__header-left" data-v-b0fb54f3><div class="tp-comments__author-name" data-v-b0fb54f3><a href="/author/45368" class="tp-comments__author-link" data-v-b0fb54f3>Григорий Гуляев</a></div><div class="tp-comments__date" data-v-b0fb54f3><div class="tp-date tp-date--styled" date-type="fromISO" data-v-e8bf1fd6 data-v-b0fb54f3><div class="tp-tooltip" data-v-f1909e3a data-v-e8bf1fd6><!--[--><time datetime="2022-02-26T08:05:08+00:00" class="tp-date__time" data-v-e8bf1fd6>26 февр 2022</time><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>26 февр 2022 в 08:05</span></div></div></div><!----><!----><!----></div><div class="tp-comments__header-right" data-v-b0fb54f3><!--[--><div style="display:none;" class="tp-comments-item__header-actions" data-v-63130dc8><!----><!----><!----></div><!--]--></div><!----></div><div class="tp-comments-item__body" data-v-63130dc8><a href="/author/25748" class="tp-comments-item__parent-user" data-v-63130dc8>HarleyK1ng, </a><span data-v-63130dc8>Ты БОГ!<br /></span><!----></div><div class="tp-comments-item__footer" data-v-63130dc8><button class="tp-comments-item__reply" data-v-63130dc8> Ответить </button><div class="tp-comments-votes" data-v-63130dc8 data-v-12d4d73c><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M7 20.9999V7.99993L13 2.04993C13.25 1.79993 13.5457 1.65393 13.887 1.61193C14.229 1.5706 14.5583 1.63326 14.875 1.79993C15.1917 1.9666 15.425 2.19993 15.575 2.49993C15.725 2.79993 15.7583 3.10826 15.675 3.42493L14.55 7.99993H21C21.5333 7.99993 22 8.19993 22.4 8.59993C22.8 8.99993 23 9.4666 23 9.99993V11.9999C23 12.1166 22.9833 12.2416 22.95 12.3749C22.9167 12.5083 22.8833 12.6333 22.85 12.7499L19.85 19.7999C19.7 20.1333 19.45 20.4166 19.1 20.6499C18.75 20.8833 18.3833 20.9999 18 20.9999H7ZM9 8.84993V18.9999H18L21 11.9999V9.99993H12L13.35 4.49993L9 8.84993ZM4 20.9999C3.45 20.9999 2.97933 20.8043 2.588 20.4129C2.196 20.0209 2 19.5499 2 18.9999V9.99993C2 9.44993 2.196 8.97893 2.588 8.58693C2.97933 8.1956 3.45 7.99993 4 7.99993H7V9.99993H4V18.9999H7V20.9999H4ZM9 18.9999V8.84993V18.9999Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>0</div></div><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M17 3.00007L17 16.0001L11 21.9501C10.75 22.2001 10.4543 22.3461 10.113 22.3881C9.771 22.4294 9.44167 22.3667 9.125 22.2001C8.80833 22.0334 8.575 21.8001 8.425 21.5001C8.275 21.2001 8.24167 20.8917 8.325 20.5751L9.45 16.0001L3 16.0001C2.46667 16.0001 2 15.8001 1.6 15.4001C1.2 15.0001 1 14.5334 1 14.0001L1 12.0001C1 11.8834 1.01667 11.7584 1.05 11.6251C1.08333 11.4917 1.11667 11.3667 1.15 11.2501L4.15 4.20007C4.3 3.86674 4.55 3.5834 4.9 3.35007C5.25 3.11674 5.61667 3.00007 6 3.00007L17 3.00007ZM15 15.1501L15 5.00007L6 5.00007L3 12.0001L3 14.0001L12 14.0001L10.65 19.5001L15 15.1501ZM20 3.00007C20.55 3.00007 21.0207 3.19574 21.412 3.58707C21.804 3.97907 22 4.45007 22 5.00007L22 14.0001C22 14.5501 21.804 15.0211 21.412 15.4131C21.0207 15.8044 20.55 16.0001 20 16.0001L17 16.0001L17 14.0001L20 14.0001L20 5.00007L17 5.00007L17 3.00007L20 3.00007ZM15 5.00007L15 15.1501L15 5.00007Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>0</div></div></div></div><div style="display:none;" class="tp-comments-item__answer" data-v-63130dc8><div class="tp-comments-input" data-v-63130dc8 data-v-9fc13c82><!----><div class="tp-avatar tp-avatar--own tp-avatar--circle tp-comments-input__action-avatar" style="width:48px;height:48px;" data-v-6e456a49 data-v-9fc13c82><img class="tp-avatar__image tp-avatar__image--cover" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9Ijk2IiBoZWlnaHQ9Ijk2IiByeD0iMTgiIGZpbGw9IiNGNUVFRTUiLz4KPGc+CjxwYXRoIGQ9Ik0zNy4wNjQ5IDY0LjQ4MjJWNTAuMzQ1TDUwLjM3MDUgNDQuNTIzOFYxMDUuMjMxSC01LjUzNzQxQy04LjMwOTQxIDEwMC4yNDEgLTIuNzA5OTUgODguNTk4NiA1LjI3MzQyIDgxLjk0NThDMTEuMDc4IDc4LjQ2MTQgMzcuMDY0OSA2OC42NDAyIDM3LjA2NDkgNjQuNDgyMloiIGZpbGw9IiNFNkMxOUMiLz4KPHBhdGggZD0iTTU4LjY4NyA2NC40ODIyQzU3LjI2ODkgNjEuNDczMiA1OC42ODcgNTMuNjcxNCA1OC42ODcgNTAuMzQ1TDQ1LjM4MTQgNDQuNTIzOFYxMDUuMjMxTDEwMC4zNTEgMTAzLjU5MkMxMDMuMTIzIDk4LjYwMjggMTAwLjM1MSA4Ni43NjkxIDg5LjU0MDIgODAuMzA3NkM4MC4zMDk0IDc3LjUzODMgNjAuOTI0OCA2OS4yMzA2IDU4LjY4NyA2NC40ODIyWiIgZmlsbD0iI0U2QzE5QyIvPgo8cGF0aCBkPSJNNTguNjg2MSA2NS4zMTRDNDkuMzcyMSA3MS45NjY4IDQwLjM5MDkgNjguMDg2IDM3LjA2NDUgNjUuMzE0VjU2LjE2NjRMNTguNjg2MSA1MS4xNzY4VjY1LjMxNFoiIGZpbGw9IiNENUIxOEQiLz4KPHBhdGggZD0iTTI3LjkzNDEgMzMuNjQ1MUMyNy4wMjkgMjIuNDgyMSAzNS44NDQyIDEyLjkyMzEgNDcuMDQzOSAxMi45MjMxVjEyLjkyMzFDNTguMjQzNiAxMi45MjMxIDY3LjA1ODkgMjIuNDgyMSA2Ni4xNTM4IDMzLjY0NTFMNjUuNTQ3MiA0MS4xMjY4QzY1LjQwODggNDIuODMzIDY1LjEwMjkgNDQuNTIxNSA2NC42MzM5IDQ2LjE2NzhMNjIuMDkxMyA1NS4wOTI0QzYwLjIyNzYgNjEuNjMzOCA1NC4yNTEgNjYuMTQ1NSA0Ny40NDkyIDY2LjE0NTVWNjYuMTQ1NUM0MC45OTU5IDY2LjE0NTUgMzUuMjQzNiA2Mi4wNzcgMzMuMDk0IDU1Ljk5MjJMMjkuODUgNDYuODA5OEMyOS4xMTg5IDQ0Ljc0MDIgMjguNjU4OSA0Mi41ODQ2IDI4LjQ4MTUgNDAuMzk2OEwyNy45MzQxIDMzLjY0NTFaIiBmaWxsPSIjRjJDRUE1Ii8+CjwvZz4KPC9zdmc+Cg==" alt data-v-6e456a49></div><div class="tp-textarea tp-textarea--primary tp-textarea--elastic tp-textarea--actions-right tp-textarea--actions tp-comments-input__textarea" data-v-14c4c8fc data-v-9fc13c82><label class="tp-textarea__label tp-textarea__label--extra-small" data-v-14c4c8fc> <span class="tp-textarea__textarea-container" data-v-14c4c8fc><textarea cols="20" maxlength="none" minlength="none" placeholder="Комментировать..." rows="1" class="tp-textarea__textarea" data-v-14c4c8fc></textarea><span class="tp-textarea__actions" data-v-14c4c8fc><!--[--><div class="tp-comments-input__actions" data-v-9fc13c82><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" class="tp-comments-input__actions-icon" data-v-9fc13c82><!----><g fill="inherit" stroke="none"><!--[--><path fill-rule="evenodd" clip-rule="evenodd" d="M3.31775 19.6578C3.31775 20.3006 3.99052 20.7215 4.56856 20.4405L20.5102 12.6899C21.1632 12.3724 21.1632 11.442 20.5102 11.1245L4.56856 3.37385C3.99052 3.09281 3.31775 3.51379 3.31775 4.15653L3.31775 9.79016C3.31775 10.2344 3.65235 10.6073 4.09399 10.6553L11.1265 11.4197C11.3752 11.4468 11.5637 11.6569 11.5637 11.9071C11.5637 12.1573 11.3752 12.3674 11.1265 12.3944L4.09399 13.1588C3.65235 13.2068 3.31775 13.5798 3.31775 14.024L3.31775 19.6578Z" fill-color="inherit" data-v-9fc13c82></path><!--]--></g></svg></div><!--]--></span></span></label></div></div></div><!----></div><!----></div><!--]--><!----></div></div><!----></div><div id="tproger-comments-7520" class="tp-comments-item" data-v-30007e44 data-v-63130dc8><div class="tp-comments-item__avatar" data-v-63130dc8><div class="tp-avatar tp-avatar--medium tp-avatar--circle" style="width:48px;height:48px;" actual-width="48" actual-height="48" radius="50%" data-v-6e456a49 data-v-63130dc8><img class="tp-avatar__image tp-avatar__image--cover" src="https://lh3.googleusercontent.com/a/AItbvmm6b5HUpyCiGXQfH3U2yPqWGB45I0KN2QjbjYz6=s96-c" alt="Аватар пользователя Ilya Shevelev" loading="lazy" decoding="async" srcset="https://tproger.ru/signed_image/HJBMoPxZoKDVgRpdOc2td_ZAxHQttNlOYtgyatcdxvY/rs:fill:48:48:true/cb:vimg_1/f:webp/aHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUl0YnZtbTZiNUhVcHlDaUdYUWZIM1UyeVBxV0dCNDVJMEtOMlFqYmpZejY9czk2LWM 48w,https://tproger.ru/signed_image/DZ96_5pKl5Dtdm0HvNgBLTq7KauZ3IJdLn2WDwvJSb4/rs:fill:96:96:true/cb:vimg_1/f:webp/aHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUl0YnZtbTZiNUhVcHlDaUdYUWZIM1UyeVBxV0dCNDVJMEtOMlFqYmpZejY9czk2LWM 96w" sizes="(min-width: 0px) 48px" data-v-6e456a49></div></div><div class="tp-comments-item__content" data-v-63130dc8><div class="tp-comments__header" data-v-63130dc8 data-v-b0fb54f3><div class="tp-comments__header-left" data-v-b0fb54f3><div class="tp-comments__author-name" data-v-b0fb54f3><a href="/author/55689" class="tp-comments__author-link" data-v-b0fb54f3>Ilya Shevelev</a></div><div class="tp-comments__date" data-v-b0fb54f3><div class="tp-date tp-date--styled" date-type="fromISO" data-v-e8bf1fd6 data-v-b0fb54f3><div class="tp-tooltip" data-v-f1909e3a data-v-e8bf1fd6><!--[--><time datetime="2022-08-23T16:53:19+00:00" class="tp-date__time" data-v-e8bf1fd6>23 авг 2022</time><!--]--><span class="tp-tooltip__popover tp-tooltip__popover--top" style="display:none;" data-v-f1909e3a data-v-f1909e3a>23 авг 2022 в 16:53</span></div></div></div><!----><!----><!----></div><div class="tp-comments__header-right" data-v-b0fb54f3><!--[--><div style="display:none;" class="tp-comments-item__header-actions" data-v-63130dc8><!----><!----><!----></div><!--]--></div><!----></div><div class="tp-comments-item__body" data-v-63130dc8><!----><span data-v-63130dc8><div>Здравствуйте. Когда я выполняю команду npm run dev происходит ошибка: пишется, что нужно добавить либо параметр presets(как здесь), либо plugins в .babelrs чтобы использовать JSX. Я пробовал и с тем, и с другим, и с обоими, и подключал JSX-файл с сайта реакта - выдает ту же ошибку. С npm run build тоже не получается.<br /></div><div><br /></div><div><br /></div><div><br /></div>ERROR in ../../../Dropbox/ПК/Desktop/django-react/frontend/src/components/App.js
Module build failed (from ../../../Dropbox/ПК/Desktop/django-react/frontend/node_modules/babel-loader/lib/index.js):
SyntaxError: C:\Users\Илья\Dropbox\ПК\Desktop\django-react\frontend\src\components\App.js: Support for the experimental syntax 'jsx' isn't currently enabled (36:7):

  34 |   render() {
  35 |     return (
> 36 |       
     |       ^
  37 |         {this.state.data.map(contact => {
  38 |           return (
  39 |             

Add @babel/preset-react (https://github.com/babel/babel/tree/main/packages/babel-preset-react) to the 'presets' section of your Babel config to enable transformation.
If you want to leave it as-is, add @babel/plugin-syntax-jsx (https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-jsx) to the 'plugins' section to enable parsing.<div><br /></div><div><br /></div>(ВВОД)    npm run dev<div><br /></div>(ВЫВОД)    > frontend@1.0.0 dev
> webpack --mode development --entry ./src/index.js --output-path ./static/frontend

[webpack-cli] [Error: EISDIR: illegal operation on a directory, open 'C:\Users\Илья\Desktop\django-react\frontend\static\frontend\main.js'] {
  errno: -4068,
  code: 'EISDIR',
  syscall: 'open',
  path: 'C:\\Users\\Илья\\Desktop\\django-react\\frontend\\static\\frontend\\main.js'
}<div><br /></div><div><br /></div><div>Помогите, кто знает. Надеюсь на отзывчивость. Заранее спасибо!</div></span><!----></div><div class="tp-comments-item__footer" data-v-63130dc8><button class="tp-comments-item__reply" data-v-63130dc8> Ответить </button><div class="tp-comments-votes" data-v-63130dc8 data-v-12d4d73c><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M7 20.9999V7.99993L13 2.04993C13.25 1.79993 13.5457 1.65393 13.887 1.61193C14.229 1.5706 14.5583 1.63326 14.875 1.79993C15.1917 1.9666 15.425 2.19993 15.575 2.49993C15.725 2.79993 15.7583 3.10826 15.675 3.42493L14.55 7.99993H21C21.5333 7.99993 22 8.19993 22.4 8.59993C22.8 8.99993 23 9.4666 23 9.99993V11.9999C23 12.1166 22.9833 12.2416 22.95 12.3749C22.9167 12.5083 22.8833 12.6333 22.85 12.7499L19.85 19.7999C19.7 20.1333 19.45 20.4166 19.1 20.6499C18.75 20.8833 18.3833 20.9999 18 20.9999H7ZM9 8.84993V18.9999H18L21 11.9999V9.99993H12L13.35 4.49993L9 8.84993ZM4 20.9999C3.45 20.9999 2.97933 20.8043 2.588 20.4129C2.196 20.0209 2 19.5499 2 18.9999V9.99993C2 9.44993 2.196 8.97893 2.588 8.58693C2.97933 8.1956 3.45 7.99993 4 7.99993H7V9.99993H4V18.9999H7V20.9999H4ZM9 18.9999V8.84993V18.9999Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>2</div></div><div class="tp-comments-votes-item tp-comments__vote" data-v-12d4d73c><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" role="presentation" class="tp-comments__vote-icon" data-v-12d4d73c><!----><g fill="inherit" stroke="none"><!--[--><path d="M17 3.00007L17 16.0001L11 21.9501C10.75 22.2001 10.4543 22.3461 10.113 22.3881C9.771 22.4294 9.44167 22.3667 9.125 22.2001C8.80833 22.0334 8.575 21.8001 8.425 21.5001C8.275 21.2001 8.24167 20.8917 8.325 20.5751L9.45 16.0001L3 16.0001C2.46667 16.0001 2 15.8001 1.6 15.4001C1.2 15.0001 1 14.5334 1 14.0001L1 12.0001C1 11.8834 1.01667 11.7584 1.05 11.6251C1.08333 11.4917 1.11667 11.3667 1.15 11.2501L4.15 4.20007C4.3 3.86674 4.55 3.5834 4.9 3.35007C5.25 3.11674 5.61667 3.00007 6 3.00007L17 3.00007ZM15 15.1501L15 5.00007L6 5.00007L3 12.0001L3 14.0001L12 14.0001L10.65 19.5001L15 15.1501ZM20 3.00007C20.55 3.00007 21.0207 3.19574 21.412 3.58707C21.804 3.97907 22 4.45007 22 5.00007L22 14.0001C22 14.5501 21.804 15.0211 21.412 15.4131C21.0207 15.8044 20.55 16.0001 20 16.0001L17 16.0001L17 14.0001L20 14.0001L20 5.00007L17 5.00007L17 3.00007L20 3.00007ZM15 5.00007L15 15.1501L15 5.00007Z" data-v-12d4d73c></path><!--]--></g></svg><div class="tp-comments__vote-count" data-v-12d4d73c>1</div></div></div></div><div style="display:none;" class="tp-comments-item__answer" data-v-63130dc8><div class="tp-comments-input" data-v-63130dc8 data-v-9fc13c82><!----><div class="tp-avatar tp-avatar--own tp-avatar--circle tp-comments-input__action-avatar" style="width:48px;height:48px;" data-v-6e456a49 data-v-9fc13c82><img class="tp-avatar__image tp-avatar__image--cover" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9Ijk2IiBoZWlnaHQ9Ijk2IiByeD0iMTgiIGZpbGw9IiNGNUVFRTUiLz4KPGc+CjxwYXRoIGQ9Ik0zNy4wNjQ5IDY0LjQ4MjJWNTAuMzQ1TDUwLjM3MDUgNDQuNTIzOFYxMDUuMjMxSC01LjUzNzQxQy04LjMwOTQxIDEwMC4yNDEgLTIuNzA5OTUgODguNTk4NiA1LjI3MzQyIDgxLjk0NThDMTEuMDc4IDc4LjQ2MTQgMzcuMDY0OSA2OC42NDAyIDM3LjA2NDkgNjQuNDgyMloiIGZpbGw9IiNFNkMxOUMiLz4KPHBhdGggZD0iTTU4LjY4NyA2NC40ODIyQzU3LjI2ODkgNjEuNDczMiA1OC42ODcgNTMuNjcxNCA1OC42ODcgNTAuMzQ1TDQ1LjM4MTQgNDQuNTIzOFYxMDUuMjMxTDEwMC4zNTEgMTAzLjU5MkMxMDMuMTIzIDk4LjYwMjggMTAwLjM1MSA4Ni43NjkxIDg5LjU0MDIgODAuMzA3NkM4MC4zMDk0IDc3LjUzODMgNjAuOTI0OCA2OS4yMzA2IDU4LjY4NyA2NC40ODIyWiIgZmlsbD0iI0U2QzE5QyIvPgo8cGF0aCBkPSJNNTguNjg2MSA2NS4zMTRDNDkuMzcyMSA3MS45NjY4IDQwLjM5MDkgNjguMDg2IDM3LjA2NDUgNjUuMzE0VjU2LjE2NjRMNTguNjg2MSA1MS4xNzY4VjY1LjMxNFoiIGZpbGw9IiNENUIxOEQiLz4KPHBhdGggZD0iTTI3LjkzNDEgMzMuNjQ1MUMyNy4wMjkgMjIuNDgyMSAzNS44NDQyIDEyLjkyMzEgNDcuMDQzOSAxMi45MjMxVjEyLjkyMzFDNTguMjQzNiAxMi45MjMxIDY3LjA1ODkgMjIuNDgyMSA2Ni4xNTM4IDMzLjY0NTFMNjUuNTQ3MiA0MS4xMjY4QzY1LjQwODggNDIuODMzIDY1LjEwMjkgNDQuNTIxNSA2NC42MzM5IDQ2LjE2NzhMNjIuMDkxMyA1NS4wOTI0QzYwLjIyNzYgNjEuNjMzOCA1NC4yNTEgNjYuMTQ1NSA0Ny40NDkyIDY2LjE0NTVWNjYuMTQ1NUM0MC45OTU5IDY2LjE0NTUgMzUuMjQzNiA2Mi4wNzcgMzMuMDk0IDU1Ljk5MjJMMjkuODUgNDYuODA5OEMyOS4xMTg5IDQ0Ljc0MDIgMjguNjU4OSA0Mi41ODQ2IDI4LjQ4MTUgNDAuMzk2OEwyNy45MzQxIDMzLjY0NTFaIiBmaWxsPSIjRjJDRUE1Ii8+CjwvZz4KPC9zdmc+Cg==" alt data-v-6e456a49></div><div class="tp-textarea tp-textarea--primary tp-textarea--elastic tp-textarea--actions-right tp-textarea--actions tp-comments-input__textarea" data-v-14c4c8fc data-v-9fc13c82><label class="tp-textarea__label tp-textarea__label--extra-small" data-v-14c4c8fc> <span class="tp-textarea__textarea-container" data-v-14c4c8fc><textarea cols="20" maxlength="none" minlength="none" placeholder="Комментировать..." rows="1" class="tp-textarea__textarea" data-v-14c4c8fc></textarea><span class="tp-textarea__actions" data-v-14c4c8fc><!--[--><div class="tp-comments-input__actions" data-v-9fc13c82><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" class="tp-comments-input__actions-icon" data-v-9fc13c82><!----><g fill="inherit" stroke="none"><!--[--><path fill-rule="evenodd" clip-rule="evenodd" d="M3.31775 19.6578C3.31775 20.3006 3.99052 20.7215 4.56856 20.4405L20.5102 12.6899C21.1632 12.3724 21.1632 11.442 20.5102 11.1245L4.56856 3.37385C3.99052 3.09281 3.31775 3.51379 3.31775 4.15653L3.31775 9.79016C3.31775 10.2344 3.65235 10.6073 4.09399 10.6553L11.1265 11.4197C11.3752 11.4468 11.5637 11.6569 11.5637 11.9071C11.5637 12.1573 11.3752 12.3674 11.1265 12.3944L4.09399 13.1588C3.65235 13.2068 3.31775 13.5798 3.31775 14.024L3.31775 19.6578Z" fill-color="inherit" data-v-9fc13c82></path><!--]--></g></svg></div><!--]--></span></span></label></div></div></div><!----></div><!----></div><!--]--><div class="tp-comments-list__more" data-v-30007e44> Показать все комментарии <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="presentation" data-v-30007e44><!----><g fill="none" stroke="inherit"><!--[--><path d="M9 11L12.5 14L16 11" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-30007e44></path><!--]--></g></svg></div></div></div></div></div></div><div class="tp-post-page__widgets tp-post-page__widgets--is-empty" data-v-a1103d06><!--[--><!--]--><!----></div></div><!--]--></main><aside class="tp-layout-default__aside-right"><div class="tp-layout-default__widget-container" data-v-18cca497><div class="tp-layout-default__listok-container" data-v-18cca497><span data-v-18cca497></span></div><span data-v-18cca497></span></div></aside></div><!--teleport start--><!--teleport end--><span></span><span></span><!--teleport start--><!--teleport end--></div></div><script>window.__NUXT__=(function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P){x[0]="popup";x[1]="fix";x[2]="after_post";x[3]="top";return {data:{"/v1/options{\"method\":\"GET\",\"query\":{\"link\":\"L3RyYW5zbGF0aW9ucy9kamFuZ28tcmVhY3Qtd2ViYXBw\"}}":{isShowAd:g,availableBannerPositions:x},"/v1/post/single/{\"method\":\"GET\",\"params\":{\"name\":\"django-react-webapp\",\"tag\":\"translations\"}}":{id:128591,title:"Пишем приложение с бэкендом на Django и фронтендом на React",status:"publish",authorId:d,link:y,linkV2:y,linkIsExternal:a,excerpt:z,view:91770,bookmarks:{count:74,added:a},content:"{\"blocks\":[{\"type\":\"paragraph\",\"data\":{\"text\":\"Автор перевода Полина Ревякина, копирайтер в Skillbox\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"В этом материале вы узнаете:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"как создать бэкенд с REST API на Django;\",\"как добавить React в проект Django;\",\"как соединить бэкенд на Django и фронт на React.\"],\"style\":\"unordered\"}},{\"type\":\"list\",\"data\":{\"items\":[\"\u003Ca href=\\\"#part1\\\"\u003EПодготовка\u003C\u002Fa\u003E\",\"\u003Ca href=\\\"#part2\\\"\u003EСоздаём проект Django в виртуальном окружении Python\u003C\u002Fa\u003E\",\"\u003Ca href=\\\"#part3\\\"\u003EПишем приложение на Django\u003C\u002Fa\u003E\",\"\u003Ca href=\\\"#part4\\\"\u003EСоединяем Django и React\u003C\u002Fa\u003E\",\"\u003Ca href=\\\"#part5\\\"\u003EУстанавливаем React и webpack\u003C\u002Fa\u003E\",\"\u003Ca href=\\\"#part6\\\"\u003EГотовим приложение Django для фронтенда\u003C\u002Fa\u003E\",\"\u003Ca href=\\\"#part7\\\"\u003EФронтенд на React\u003C\u002Fa\u003E\",\"\u003Ca href=\\\"#part8\\\"\u003EЗаключение\u003C\u002Fa\u003E\"],\"style\":\"ordered\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Подготовка\"},\"tunes\":{\"anchorTune\":{\"anchor\":\"part1\"}}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Вам понадобятся:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"базовое понимание Python и Джанго;\",\"базовое понимание JavaScript (и спецификации ECMAScript 2015) и React;\",\"установленный Node.js.\"],\"style\":\"unordered\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Создаём проект Django в виртуальном окружении Python\"},\"tunes\":{\"anchorTune\":{\"anchor\":\"part2\"}}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создайте новую папку и перейдите в неё:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Emkdir django-react && cd $_\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Потом активируйте виртуальное окружение Python:\"}},{\"type\":\"code\",\"data\":{\"code\":\"python3 -m venv venv\\r\\nsource venv\u002Fbin\u002Factivate\",\"language\":\"bash lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Cu is=\\\"tp-badge\\\" class=\\\"tp-badge tp-badge--first-variant\\\" data-color=\\\"firstVariant\\\"\u003EПримечание\u003C\u002Fu\u003E все следующие команды нужно выполнять из папки \u003Ccode class=\\\"\\\"\u003Edjango-react\u003C\u002Fcode\u003E и с активированным виртуальным окружением.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Установите зависимости Джанго и Django REST Framework:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Epip install django djangorestframework\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"После установки создайте новый проект Django:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Edjango-admin startproject django_react\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Теперь сделаем API на Django для создания и хранения контактов.\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Пишем приложение с бэкендом на Django\"},\"tunes\":{\"anchorTune\":{\"anchor\":\"part3\"}}},{\"type\":\"paragraph\",\"data\":{\"text\":\"В каждом проекте Django может быть много приложений. Приложения можно делать переиспользуемыми: такими, что их можно добавить в менеджер пакетов Python и установить через него в другой проект, в котором нужно такое приложение.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Для создания нового приложения Django используется команда:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Edjango-admin startapp app_name\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"где \u003Ccode class=\\\"\\\"\u003Eapp_name\u003C\u002Fcode\u003E — название приложения.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"В нашем случае команда будет выглядеть так:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Edjango-admin startapp leads\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Она создаст приложение \u003Ccode class=\\\"\\\"\u003Eleads\u003C\u002Fcode\u003E в папке \u003Ccode class=\\\"\\\"\u003Edjango-react\u003C\u002Fcode\u003E. Теперь структура папок в проекте должна выглядеть так:\"}},{\"type\":\"code\",\"data\":{\"code\":\"(venv) your@prompt:~\u002FCode\u002Fdjango-react$ tree -d -L 1\\r\\n.\\r\\n├── django_react\\r\\n├── leads\\r\\n└── venv\",\"language\":\"bash lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Теперь сделаем так, чтобы Django проект использовал новое приложение. Откройте файл \u003Ccode class=\\\"\\\"\u003Edjango_react\u002Fsettings.py\u003C\u002Fcode\u003E и добавьте приложение в \u003Ccode class=\\\"\\\"\u003EINSTALLED_APPS\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"INSTALLED_APPS = [\\r\\n    'django.contrib.admin',\\r\\n    'django.contrib.auth',\\r\\n    'django.contrib.contenttypes',\\r\\n    'django.contrib.sessions',\\r\\n    'django.contrib.messages',\\r\\n    'django.contrib.staticfiles',\\r\\n    'leads.apps.LeadsConfig', # activate the new app\\r\\n]\",\"language\":\"python lazy-code\"}},{\"type\":\"header3\",\"data\":{\"level\":3,\"text\":\"Создаём модель в базе данных с Джанго\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Модель — это объект, представляющий собой данные из таблицы. Почти каждый веб-фреймворк использует модели, и Django — не исключение. Она может иметь одно или больше полей. Каждое поле соответствует полю в таблице.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Мы собираемся хранить контакты, поэтому модель \u003Ccode class=\\\"\\\"\u003ELead\u003C\u002Fcode\u003E может состоять из этих полей:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"имя;\",\"email;\",\"сообщение.\"],\"style\":\"unordered\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Добавим ещё поле со временем создания модели, потому что по умолчанию Django этого не делает.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Откроем \u003Ccode class=\\\"\\\"\u003Eleads\u002Fmodels.py\u003C\u002Fcode\u003E и опишем модель \u003Ccode class=\\\"\\\"\u003ELead\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"from django.db import models\\r\\n\\r\\nclass Lead(models.Model):\\r\\n    name = models.CharField(max_length=100)\\r\\n    email = models.EmailField()\\r\\n    message = models.CharField(max_length=300)\\r\\n    created_at = models.DateTimeField(auto_now_add=True)\",\"language\":\"clike lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Cu is=\\\"tp-badge\\\" class=\\\"tp-badge tp-badge--first-variant\\\" data-color=\\\"firstVariant\\\"\u003EПримечание\u003C\u002Fu\u003E \u003Ca href=\\\"https:\u002F\u002Fdocs.djangoproject.com\u002Fen\u002Fdev\u002Fref\u002Fmodels\u002Ffields\u002F\\\"\u003Eизучите\u003C\u002Fa\u003E документацию Django о полях. Когда придумываете структуру модели, выбирайте самые подходящие для вашего случая поля.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создадим миграции командой:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Epython manage.py makemigrations leads\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"и применим их к базе данных:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Epython manage.py migrate\u003C\u002Fcode\u003E\"}},{\"type\":\"header3\",\"data\":{\"level\":3,\"text\":\"Займёмся тестированием\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Вы могли подумать «А как же тестирование?».\"}},{\"type\":\"embed\",\"data\":{\"link\":\"https:\u002F\u002Ftproger.ru\u002Ftranslations\u002Ftest-driven-development-is-dumb\u002F\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Существует масса туториалов по бэкенду на Джанго, начинающихся примерно так:\"}},{\"type\":\"code\",\"data\":{\"code\":\"class SomeModelModelTest(TestCase):\\r\\n    def setUp(self):\\r\\n        SomeModel.objects.create(\\r\\n            name=fake.name(),\\r\\n            email=fake.email(),\\r\\n            phone=fake.phone_number(),\\r\\n            message=fake.text(),\\r\\n            source=fake.url()\\r\\n        )\\r\\n    def test_save_model(self):\\r\\n        saved_models = SomeModel.objects.count()\\r\\n        self.assertEqual(saved_models, 2)\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Не надо так. Нет никакого смысла ни в тестировании стандартной модели Django, ни в тестировании Django ORM. Что точно не нужно тестировать при создании приложения с бэкендом на Django:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"встроенный код Django (модели, представления);\",\"встроенные функции Python.\"],\"style\":\"unordered\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Не тестируйте то, что уже протестировано! Так что же тогда тестировать?\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Добавили свой метод в модель Django — протестируйте его. Дополнили стандартное представление — протестируйте его. Но как узнать, что именно нужно протестировать?\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Узнать это поможет библиотека coverage. Установите её:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Epip install coverage\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Теперь после каждого добавления или изменения кода запускайте \u003Ccode class=\\\"\\\"\u003Ecoverage\u003C\u002Fcode\u003E:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Ecoverage run --source='.' manage.py test\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"и создавайте отчёт:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Ecoverage html\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Вы увидите, что именно нужно протестировать. Если предпочитаете увидеть отчёт в командной строке, запустите команду:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Ecoverage report\u003C\u002Fcode\u003E\"}},{\"type\":\"header3\",\"data\":{\"level\":3,\"text\":\"Сериализаторы Django\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Сериализация — это конвертация объекта Python в другой формат. После сериализации можно сохранить объект в файл или послать его через сеть.\"}},{\"type\":\"embed\",\"data\":{\"link\":\"https:\u002F\u002Ftproger.ru\u002Fexperts\u002Festimate-programmers-competence-with-several-questions\u002F\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Почему сериализация необходима? Модель Джанго — это класс Python. Чтобы превратить её в данные в формате JSON, нужна сериализация.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Сериализаторы работают и в обратном направлении: они конвертируют JSON в объекты. Это позволяет:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"отображать модель Django в браузере с помощью конвертации в JSON;\",\"делать запросы CRUD (create – read – update – delete) к API в формате JSON.\"],\"style\":\"unordered\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Суммируя: сериализаторы в Django можно использовать для совершения операций с моделями Django через API.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создайте новый файл \u003Ccode class=\\\"\\\"\u003Eleads\u002Fserializers.py\u003C\u002Fcode\u003E. Сериализатор \u003Ccode class=\\\"\\\"\u003ELeadSerializer\u003C\u002Fcode\u003E содержит нашу модель и поля:\"}},{\"type\":\"code\",\"data\":{\"code\":\"from rest_framework import serializers\\r\\nfrom .models import Lead\\r\\n\\r\\nclass LeadSerializer(serializers.ModelSerializer):\\r\\n    class Meta:\\r\\n        model = Lead\\r\\n        fields = ('id', 'name', 'email', 'message')\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Созданный дочерний класс от класса \u003Ccode class=\\\"\\\"\u003Eserializers.ModelSerializer\u003C\u002Fcode\u003E. \u003Ccode class=\\\"\\\"\u003EModelSerializer\u003C\u002Fcode\u003E в Django похож на \u003Ccode class=\\\"\\\"\u003EModelForm\u003C\u002Fcode\u003E. Он подходит, когда нужно, чтобы сериализатор соответствовал модели.\"}},{\"type\":\"header3\",\"data\":{\"level\":3,\"text\":\"Создаём представления\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Если вы раньше работали с другими фреймворками, то можете удивиться, что в Django нет контроллеров.\"}},{\"type\":\"embed\",\"data\":{\"link\":\"https:\u002F\u002Ftproger.ru\u002Ftranslations\u002Fweb-frameworks-how-to-get-started\u002F\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Контроллеры содержат логику обработки запросов и возвращения ответов. В традиционной архитектуре MVC есть модель (Model), представление (View) и контроллер (Controller). Примеры MVC фреймворков: Rails (Ruby), Phoenix (Elixir), Laravel (PHP).\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Django — это фреймворк MVT. MVT — это модель, представление и шаблон (Template). В Django есть много типов представлений: функции-представления, представления, основанные на классах, и обобщённые представления.\"}},{\"type\":\"hint\",\"data\":{\"fullWidth\":true,\"text\":\"Используйте функции-представления только если изменение обобщенных представлений займет больше, чем написание представления заново.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Мы будем использовать обобщённые представления. Наше простое приложение будет:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"возвращать выборку моделей;\",\"создавать новые объекты в базе данных.\"],\"style\":\"unordered\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"С помощью документации можно узнать, что есть представление для возвращения выборки и создания моделей: \u003Ccode class=\\\"\\\"\u003EListCreateAPIView\u003C\u002Fcode\u003E. Это представление содержит \u003Ccode class=\\\"\\\"\u003Equeryset\u003C\u002Fcode\u003E и \u003Ccode class=\\\"\\\"\u003Eserializer_class\u003C\u002Fcode\u003E.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Equeryset\u003C\u002Fcode\u003E — это выборка данных, которую приложение будет возвращать. В нашем случае — все модели \u003Ccode class=\\\"\\\"\u003ELead\u003C\u002Fcode\u003E. \u003Ccode class=\\\"\\\"\u003Eserializer_class\u003C\u002Fcode\u003E — класс сериализатора для модели.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Добавьте в файл \u003Ccode class=\\\"\\\"\u003Edjango_react\u002Fviews.py\u003C\u002Fcode\u003E следующий код:\"}},{\"type\":\"code\",\"data\":{\"code\":\"from .models import Lead\\r\\nfrom .serializers import LeadSerializer\\r\\nfrom rest_framework import generics\\r\\n\\r\\nclass LeadListCreate(generics.ListCreateAPIView):\\r\\n    queryset = Lead.objects.all()\\r\\n    serializer_class = LeadSerializer\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"С помощью трёх строк кода мы создали представление для обработки GET и POST запросов.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Чего ещё не хватает? Маршрутизации URL. Другими словами, нам нужно соединить URL и представления.\"}},{\"type\":\"header3\",\"data\":{\"level\":3,\"text\":\"Настраиваем маршрутизацию url\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Нам нужно сделать так, чтобы GET и POST запросы к \u003Ccode class=\\\"\\\"\u003Eapi\u002Flead\u002F\u003C\u002Fcode\u003E обрабатывались представлением \u003Ccode class=\\\"\\\"\u003ELeadListCreate\u003C\u002Fcode\u003E, которое будет возвращать и создавать модели.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Чтобы настроить маршрутизацию URL, отредактируйте файл \u003Ccode class=\\\"\\\"\u003Edjango_react\u002Furls.py\u003C\u002Fcode\u003E, добавив туда url приложения:\"}},{\"type\":\"code\",\"data\":{\"code\":\"from django.urls import path, include\\r\\n\\r\\nurlpatterns = [\\r\\n    path('', include('leads.urls')),\\r\\n]\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Так мы указываем в бэкенде на Django, что нужно использовать url, которые есть в приложения \u003Ccode class=\\\"\\\"\u003Eleads\u003C\u002Fcode\u003E.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Теперь создайте файл \u003Ccode class=\\\"\\\"\u003Eleads\u002Furls.py\u003C\u002Fcode\u003E. В нём мы соединим представление \u003Ccode class=\\\"\\\"\u003ELeadListCreate\u003C\u002Fcode\u003E и url \u003Ccode class=\\\"\\\"\u003Eapi\u002Flead\u002F\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"from django.urls import path\\r\\nfrom . import views\\r\\n\\r\\nurlpatterns = [\\r\\n    path('api\u002Flead\u002F', views.LeadListCreate.as_view() ),\\r\\n]\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"И наконец, включим \u003Ccode class=\\\"\\\"\u003Erest_framework\u003C\u002Fcode\u003E в \u003Ccode class=\\\"\\\"\u003EINSTALLED_APPS\u003C\u002Fcode\u003E. Откройте \u003Ccode class=\\\"\\\"\u003Edjango_react\u002Fsettings.py\u003C\u002Fcode\u003E и добавьте приложение в \u003Ccode class=\\\"\\\"\u003EINSTALLED_APPS\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"# Application definition\\r\\n\\r\\nINSTALLED_APPS = [\\r\\n    # omitted for brevity\\r\\n    'leads.apps.LeadsConfig',\\r\\n    'rest_framework'\\r\\n]\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Запустим сервер Django:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Epython manage.py runserver\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Перейдите по url http:\u002F\u002F127.0.0.1:8000\u002Fapi\u002Flead\u002F и вы увидите API:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ca href=\\\"https:\u002F\u002Fmedia.tproger.ru\u002Fuploads\u002F2020\u002F04\u002Fdjango-rest-framework-browsable-api.png\\\"\u003E\u003C\u002Fa\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Cu is=\\\"tp-badge\\\" class=\\\"tp-badge tp-badge--first-variant\\\" data-color=\\\"firstVariant\\\"\u003EПримечание\u003C\u002Fu\u003E в продакшене лучше отключить возможность просмотра API. Это можно сделать в конфигурации:\"}},{\"type\":\"code\",\"data\":{\"code\":\"REST_FRAMEWORK = {\\r\\n    'DEFAULT_RENDERER_CLASSES': (\\r\\n        'rest_framework.renderers.JSONRenderer',\\r\\n    )\\r\\n}\",\"language\":\"python lazy-code\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Соединяем Django и React\"},\"tunes\":{\"anchorTune\":{\"anchor\":\"part4\"}}},{\"type\":\"paragraph\",\"data\":{\"text\":\"У многих разработчиков возникают вопросы по поводу того, как правильно соединить Django и React.\"}},{\"type\":\"embed\",\"data\":{\"link\":\"https:\u002F\u002Ftproger.ru\u002Ftranslations\u002Fconcepts-to-become-an-advanced-react-developer\u002F\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Должен ли роутер React взять на себя маршрутизацию? Нужно ли монтировать компоненты React в каждом шаблоне Django?\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Ответ зависит от случая.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Есть следующие способы создания проекта на Django и React (они похожи почти для любого веб-фреймворка):\"}},{\"type\":\"list\",\"data\":{\"items\":[\"React в собственном приложении Django для фронтенда. Загружаем один HTML шаблон и даём React управление фронтендом (сложность: средняя).\",\"Django REST как отдельное API + React как отдельное SPA (сложность: высокая, нужна будет авторизация по JWT).\",\"Смешанный вариант: мини-приложения React в шаблонах Django (сложность: просто, но сложно будет поддерживать).\"],\"style\":\"ordered\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Если вы только начали работать с Django REST и React, избегайте варианта 2. Вместо этого выберите 1 (React в собственном приложении Django для фронтенда), если:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"вы создаёте приложение, похожее на веб-сайт;\",\"в интерфейсе будет много пользовательских действий, используется AJAX;\",\"вас устраивает авторизация, основанная на сессиях;\",\"вас не очень волнуют вопросы SEO;\",\"вас устраивает роутер React.\"],\"style\":\"unordered\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Если будете держать React близко к Django, то будет проще с авторизацией. Можно будет использовать встроенную систему авторизации Django для регистрации и входа пользователей. Используйте старую добрую авторизацию с помощью сессий и не беспокойтесь о токенах и JWT.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Выберите вариант 3 (смешанный вариант: мини-приложения React в шаблонах Django), если:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"на сайте не нужно использовать много JavaScript;\",\"вам важно SEO и вы не можете использовать Node.js для рендеринга серверной части.\"],\"style\":\"unordered\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"В данной статье мы будем использовать вариант 1.\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Устанавливаем React и webpack\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Cbr\u003EСоздадим новое приложение Django для фронтенда:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Edjango-admin startapp frontend\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Вы увидите новую папку с названием \u003Ccode class=\\\"\\\"\u003Efrontend\u003C\u002Fcode\u003E в вашей структуре папок:\"}},{\"type\":\"code\",\"data\":{\"code\":\"(venv) your@prompt:~\u002FCode\u002Fdjango-react$ tree -d -L 1\\r\\n.\\r\\n├── django_react\\r\\n├── frontend\\r\\n├── leads\\r\\n└── venv\",\"language\":\"bash lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Подготовим папки для хранения компонентов React:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Emkdir -p .\u002Ffrontend\u002Fsrc\u002Fcomponents\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"И статики:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Emkdir -p .\u002Ffrontend\u002F{static,templates}\u002Ffrontend\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Дальше установим React, webpack и babel. Перейдите в папку frontend и создайте окружение:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Ecd .\u002Ffrontend && npm init -y\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Установите webpack и webpack CLI:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Enpm i webpack webpack-cli --save-dev\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Откройте \u003Ccode class=\\\"\\\"\u003Epackage.json\u003C\u002Fcode\u003E и запишите 2 скрипта для продакшна и для разработки:\"}},{\"type\":\"code\",\"data\":{\"code\":\"\\\"scripts\\\": {\\r\\n  \\\"dev\\\": \\\"webpack --mode development .\u002Fsrc\u002Findex.js --output .\u002Fstatic\u002Ffrontend\u002Fmain.js\\\",\\r\\n  \\\"build\\\": \\\"webpack --mode production .\u002Fsrc\u002Findex.js --output .\u002Fstatic\u002Ffrontend\u002Fmain.js\\\"\\r\\n}\",\"language\":\"json lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Сохраните и закройте файл.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Установим babel, чтобы код был совместим со старыми браузерами, которые не поддерживают последние стандарты JavaScript:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Enpm i @babel\u002Fcore babel-loader @babel\u002Fpreset-env @babel\u002Fpreset-react --save-dev\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Установим React:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Enpm i react react-dom --save-dev\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Настроим Babel (по-прежнему находясь в папке \u003Ccode class=\\\"\\\"\u003Efrontend\u003C\u002Fcode\u003E):\"}},{\"type\":\"code\",\"data\":{\"code\":\"{\\r\\n    \\\"presets\\\": [\\r\\n        \\\"@babel\u002Fpreset-env\\\", \\\"@babel\u002Fpreset-react\\\"\\r\\n    ]\\r\\n}\",\"language\":\"json lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создадим файл \u003Ccode class=\\\"\\\"\u003Ewebpack.config.js\u003C\u002Fcode\u003E для настройки загрузчика babel:\"}},{\"type\":\"code\",\"data\":{\"code\":\"module.exports = {\\r\\n  module: {\\r\\n    rules: [\\r\\n      {\\r\\n        test: \u002F\\\\.js$\u002F,\\r\\n        exclude: \u002Fnode_modules\u002F,\\r\\n        use: {\\r\\n          loader: \\\"babel-loader\\\"\\r\\n        }\\r\\n      }\\r\\n    ]\\r\\n  }\\r\\n};\",\"language\":\"json lazy-code\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Готовим приложение Django для фронтенда\"},\"tunes\":{\"anchorTune\":{\"anchor\":\"part6\"}}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создадим представление в \u003Ccode class=\\\"\\\"\u003E.\u002Ffrontend\u002Fviews.py\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"from django.shortcuts import render\\r\\n\\r\\n\\r\\ndef index(request):\\r\\n    return render(request, 'frontend\u002Findex.html')\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создадим шаблон в \u003Ccode class=\\\"\\\"\u003E.\u002Ffrontend\u002Ftemplates\u002Ffrontend\u002Findex.html\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"\u003C!DOCTYPE html\u003E\\r\\n\u003Chtml\u003E\\r\\n\u003Chead\u003E\\r\\n  \u003Cmeta charset=\\\"utf-8\\\"\u003E\\r\\n  \u003Cmeta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\"\u003E\\r\\n  \u003Ctitle\u003EDjango REST with React\\r\\n\u003C\u002Fhead\u003E\\r\\n\u003Cbody\u003E\\r\\n\u003Cdiv id=\\\"app\\\"\u003E\\r\\n    \u003C!-- React will load here --\u003E\\r\\n\u003C\u002Fdiv\u003E\\r\\n\u003C\u002Fbody\u003E\\r\\n{% load static %}\\r\\n\u003Cscript src=\\\"{% static \\\"frontend\u002Fmain.js\\\" %}\\\"\u003E\u003C\u002Fscript\u003E\\r\\n\u003C\u002Fhtml\u003E\",\"language\":\"clike lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"В шаблоне вызывается \u003Ccode class=\\\"\\\"\u003E.\u002Ffrontend\u002Fmain.js\u003C\u002Fcode\u003E — файл, который будет генерировать webpack, содержащий весь код на React.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Настроим маршрутизатор Django: включим туда url приложения frontend. Отредактируем файл \u003Ccode class=\\\"\\\"\u003E.\u002Fproject\u002Furls.py\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"urlpatterns = [\\r\\n    path('', include('leads.urls')),\\r\\n    path('', include('frontend.urls')),\\r\\n]\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создадим файл \u003Ccode class=\\\"\\\"\u003E.\u002Ffrontend\u002Furls.py\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"from django.urls import path\\r\\nfrom . import views\\r\\n\\r\\n\\r\\nurlpatterns = [\\r\\n    path('', views.index ),\\r\\n]\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Включим приложение фронтенда в список используемых приложений в файле \u003Ccode class=\\\"\\\"\u003E.\u002Fproject\u002Fsettings.py\u003C\u002Fcode\u003E:\"}},{\"type\":\"code\",\"data\":{\"code\":\"# Application definition\\r\\n\\r\\nINSTALLED_APPS = [\\r\\n    'leads.apps.LeadsConfig',\\r\\n    'rest_framework',\\r\\n    'frontend', # enable the frontend app\\r\\n]\",\"language\":\"python lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Зайдя на http:\u002F\u002F127.0.0.1:8000\u002F, вы увидите пока что просто пустую страницу (для этого сервер Django должен продолжать работать).\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Фронтенд на React\"},\"tunes\":{\"anchorTune\":{\"anchor\":\"part7\"}}},{\"type\":\"paragraph\",\"data\":{\"text\":\"После бэкенда, написанного на Джанго, сделаем простой компонент React, который будет отображать наши данные. Если ваша база данных пуста, то самое время наполнить приложение какими-нибудь данными.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Запустите сервер Django и перейдите на http:\u002F\u002F127.0.0.1:8000\u002Fapi\u002Flead\u002F чтобы добавить контакты.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Создадим файл \u003Ccode class=\\\"\\\"\u003E.\u002Ffrontend\u002Fsrc\u002Fcomponents\u002FApp.js\u003C\u002Fcode\u003E. В нём будет компонент React, запрашивающий и отображающий данные.\"}},{\"type\":\"code\",\"data\":{\"code\":\"import React, { Component } from 'react';\\r\\nimport { render } from \\\"react-dom\\\";\\r\\n\\r\\nclass App extends Component {\\r\\n  constructor(props) {\\r\\n    super(props);\\r\\n    this.state = {\\r\\n      data: [],\\r\\n      loaded: false,\\r\\n      placeholder: \\\"Loading\\\"\\r\\n    };\\r\\n  }\\r\\n\\r\\n  componentDidMount() {\\r\\n    fetch(\\\"api\u002Flead\\\")\\r\\n      .then(response =\u003E {\\r\\n        if (response.status \u003E 400) {\\r\\n          return this.setState(() =\u003E {\\r\\n            return { placeholder: \\\"Something went wrong!\\\" };\\r\\n          });\\r\\n        }\\r\\n        return response.json();\\r\\n      })\\r\\n      .then(data =\u003E {\\r\\n        this.setState(() =\u003E {\\r\\n          return {\\r\\n            data,\\r\\n            loaded: true\\r\\n          };\\r\\n        });\\r\\n      });\\r\\n  }\\r\\n\\r\\n  render() {\\r\\n    return (\\r\\n      \u003Cul\u003E\\r\\n        {this.state.data.map(contact =\u003E {\\r\\n          return (\\r\\n            \u003Cli key={contact.id}\u003E\\r\\n              {contact.name} - {contact.email}\\r\\n            \u003C\u002Fli\u003E\\r\\n          );\\r\\n        })}\\r\\n      \u003C\u002Ful\u003E\\r\\n    );\\r\\n  }\\r\\n}\\r\\n\\r\\nexport default App;\\r\\n\\r\\nconst container = document.getElementById(\\\"app\\\");\\r\\nrender(\u003CApp \u002F\u003E, container);\",\"language\":\"javascript lazy-code\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Cu is=\\\"tp-badge\\\" class=\\\"tp-badge tp-badge--first-variant\\\" data-color=\\\"firstVariant\\\"\u003EПримечание\u003C\u002Fu\u003E можно написать тот же компонент в виде функции с хуком \u003Ccode class=\\\"\\\"\u003EuseEffect\u003C\u002Fcode\u003E.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Сохраните и закройте файл. Теперь создайте точку входа для webpack — файл \u003Ccode class=\\\"\\\"\u003E.\u002Ffrontend\u002Fsrc\u002Findex.js\u003C\u002Fcode\u003E и импортируйте компонент:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Eimport App from ".\u002Fcomponents\u002FApp"\u003C\u002Fcode\u003E;\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Теперь можно протестировать результат. Запустите webpack:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Enpm run dev\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Запустите сервер Django:\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ccode class=\\\"\\\"\u003Epython manage.py runserver\u003C\u002Fcode\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Перейдите на http:\u002F\u002F127.0.0.1:8000\u002F. Если вы видите сообщение «Что-то пошло не так», то убедитесь, что применили миграции и заполнили базу данных. Вы должны увидеть данные, отображенные компонентом React.\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"\u003Ca href=\\\"https:\u002F\u002Fmedia.tproger.ru\u002Fuploads\u002F2020\u002F04\u002Fdjango-rest-react.png\\\"\u003E\u003C\u002Fa\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Выглядит просто. И работает!\"}},{\"type\":\"header2\",\"data\":{\"level\":2,\"text\":\"Заключение\"},\"tunes\":{\"anchorTune\":{\"anchor\":\"part8\"}}},{\"type\":\"paragraph\",\"data\":{\"text\":\"В этом материале мы сделали простой проект на Django REST API и React. Мы научились:\"}},{\"type\":\"list\",\"data\":{\"items\":[\"создавать простое REST API на Django;\",\"добавлять React в проект Django;\",\"соединять Django REST API и React.\"],\"style\":\"unordered\"}},{\"type\":\"raw\",\"data\":{\"html\":\"\u003Chr\u003E\u003C\u002Fhr\u003E\"}},{\"type\":\"paragraph\",\"data\":{\"text\":\"Если этот проект показался сложным, попробуйте другой туториал. В нём мы показали, \u003Ca href=\\\"https:\u002F\u002Ftproger.ru\u002Ftranslations\u002Fcreate-your-first-django-app\u002F\\\"\u003Eкак создать первое веб-приложение на Django\u003C\u002Fa\u003E.\"}}]}",comments:A,reactions:[{count:e,key:"angry",order:d,is_selected:a},{count:e,key:"surprised",order:q,is_selected:a},{count:e,key:"thinking",order:3,is_selected:a},{count:e,key:"laugh",order:B,is_selected:a},{count:21,key:"like",order:C,is_selected:a}],isPin:a,publishDate:1588325173,tags:[{id:40,slug:"for-beginners",name:"Для начинающих",isSubscribe:a},{id:54,slug:"web",name:"Веб-разработка",isSubscribe:a},{id:107,slug:"python",name:"Python",isSubscribe:a},{id:329,slug:"django",name:"Django",isSubscribe:a},{id:355,slug:"react",name:"React",isSubscribe:a}],meta:{disableAds:a},seo:{title:"Бэкенд на Django и фронтенд на React: пишем приложение",description:z},sandbox:b,icon:{src:"https:\u002F\u002Fmedia.tproger.ru\u002Fuploads\u002F2020\u002F04\u002Ficonfinder-icon-28-cover-icon.png",color:"#b4c3f7",width:e,height:90,srcset:[]}},"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/translations/test-driven-development-is-dumb/\"}}":{title:"Мнение: разработка через тестирование — это тупо. Обсуждаем TDD",link:"https:\u002F\u002Ftproger.ru\u002Ftranslations\u002Ftest-driven-development-is-dumb\u002F",postType:k,imageUrl:b,vacancyMeta:b,eventMeta:b,viewDomain:m,type:n},"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/experts/estimate-programmers-competence-with-several-questions/\"}}":{title:"Как оценить профессионализм программиста за 5 вопросов — отвечают эксперты",link:"https:\u002F\u002Ftproger.ru\u002Fexperts\u002Festimate-programmers-competence-with-several-questions\u002F",postType:k,imageUrl:b,vacancyMeta:b,eventMeta:b,viewDomain:m,type:n},"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/translations/web-frameworks-how-to-get-started/\"}}":{title:"Веб-фреймворки для начинающих: простое объяснение с примерами",link:"https:\u002F\u002Ftproger.ru\u002Ftranslations\u002Fweb-frameworks-how-to-get-started\u002F",postType:k,imageUrl:b,vacancyMeta:b,eventMeta:b,viewDomain:m,type:n},"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/translations/concepts-to-become-an-advanced-react-developer/\"}}":{title:"React: практики, которые помогут стать продвинутым разработчиком",link:"https:\u002F\u002Ftproger.ru\u002Ftranslations\u002Fconcepts-to-become-an-advanced-react-developer\u002F",postType:k,imageUrl:b,vacancyMeta:b,eventMeta:b,viewDomain:m,type:n},"/v1/comments/post/128591{\"lazy\":true}":{postAuthor:80066,count:A,comments:[{id:5993,content:"В части про настройку Bable тоже нет важного для новичков куска текста.\" \"presets\": [  ... \" - Нужно класть в файл конфигураций babel, который не создается автоматически, а его нужно создать в этой же директории с названием .babelrc самостоятельно и туда этот код положить. Фрагмент оригинала статьи {    Now configure babel with a .babelrc (still inside .\u002Ffrontend):}",votes:{like:{count:C,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:o,name:p,avatar:b},date:"2022-01-06T08:26:50.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]},{id:2067,content:"Вот это не будет работать:\n\"scripts\": {\n  \"dev\": \"webpack --mode development .\u002Fsrc\u002Findex.js --output .\u002Fstatic\u002Ffrontend\u002Fmain.js\",\n  \"build\": \"webpack --mode production .\u002Fsrc\u002Findex.js --output .\u002Fstatic\u002Ffrontend\u002Fmain.js\"\n}\n\n\nВместо этого пишите так:\n\"scripts\": {\n    \"dev\": \"webpack --mode development .\u002Fsrc\u002Findex.js --output-path .\u002Fstatic\u002Ffrontend\u002F\",\n    \"build\": \"webpack --mode production .\u002Fsrc\u002Findex.js --output-path .\u002Fstatic\u002Ffrontend\u002F\"\n  }\n\n\n--output устарел и вместо него используется --output-path",votes:{like:{count:B,isSelected:a},dislike:{count:d,isSelected:a}},user:{id:D,name:E,avatar:b},date:"2021-04-01T23:29:50.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[{id:6393,content:"Ты БОГ!\u003Cbr \u002F\u003E",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:45368,name:"Григорий Гуляев",avatar:{original:"https:\u002F\u002Flh3.googleusercontent.com\u002Fa\u002FAATXAJwhLUsrPnB7IueWRHe7ZS_uNNZncLlWeHPN-6vU=s96-c",alt:"Аватар пользователя Григорий Гуляев",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002F8KGdVkpUVOEOmxqa1fKuGsdw4_Z5IFSS2Vt6xLGaNz4\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd2hMVXNyUG5CN0l1ZVdSSGU3WlNfdU5OWm5jTGxXZUhQTi02dlU9czk2LWM",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FKxUIwBDSEMdCM4EhslCsaoH3xP7IIQk3fCtMhblzWoE\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd2hMVXNyUG5CN0l1ZVdSSGU3WlNfdU5OWm5jTGxXZUhQTi02dlU9czk2LWM",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},parentUser:{id:D,name:E},date:"2022-02-26T11:05:08.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]}]},{id:7520,content:"\u003Cdiv\u003EЗдравствуйте. Когда я выполняю команду npm run dev происходит ошибка: пишется, что нужно добавить либо параметр presets(как здесь), либо plugins в .babelrs чтобы использовать JSX. Я пробовал и с тем, и с другим, и с обоими, и подключал JSX-файл с сайта реакта - выдает ту же ошибку. С npm run build тоже не получается.\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003EERROR in ..\u002F..\u002F..\u002FDropbox\u002FПК\u002FDesktop\u002Fdjango-react\u002Ffrontend\u002Fsrc\u002Fcomponents\u002FApp.js\r\nModule build failed (from ..\u002F..\u002F..\u002FDropbox\u002FПК\u002FDesktop\u002Fdjango-react\u002Ffrontend\u002Fnode_modules\u002Fbabel-loader\u002Flib\u002Findex.js):\r\nSyntaxError: C:\\Users\\Илья\\Dropbox\\ПК\\Desktop\\django-react\\frontend\\src\\components\\App.js: Support for the experimental syntax 'jsx' isn't currently enabled (36:7):\r\n\r\n  34 |   render() {\r\n  35 |     return (\r\n> 36 |       \r\n     |       ^\r\n  37 |         {this.state.data.map(contact => {\r\n  38 |           return (\r\n  39 |             \r\n\r\nAdd @babel\u002Fpreset-react (https:\u002F\u002Fgithub.com\u002Fbabel\u002Fbabel\u002Ftree\u002Fmain\u002Fpackages\u002Fbabel-preset-react) to the 'presets' section of your Babel config to enable transformation.\r\nIf you want to leave it as-is, add @babel\u002Fplugin-syntax-jsx (https:\u002F\u002Fgithub.com\u002Fbabel\u002Fbabel\u002Ftree\u002Fmain\u002Fpackages\u002Fbabel-plugin-syntax-jsx) to the 'plugins' section to enable parsing.\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E(ВВОД)    npm run dev\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E(ВЫВОД)    > frontend@1.0.0 dev\r\n> webpack --mode development --entry .\u002Fsrc\u002Findex.js --output-path .\u002Fstatic\u002Ffrontend\r\n\r\n[webpack-cli] [Error: EISDIR: illegal operation on a directory, open 'C:\\Users\\Илья\\Desktop\\django-react\\frontend\\static\\frontend\\main.js'] {\r\n  errno: -4068,\r\n  code: 'EISDIR',\r\n  syscall: 'open',\r\n  path: 'C:\\\\Users\\\\Илья\\\\Desktop\\\\django-react\\\\frontend\\\\static\\\\frontend\\\\main.js'\r\n}\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E\u003Cdiv\u003E\u003Cbr \u002F\u003E\u003C\u002Fdiv\u003E\u003Cdiv\u003EПомогите, кто знает. Надеюсь на отзывчивость. Заранее спасибо!\u003C\u002Fdiv\u003E",votes:{like:{count:q,isSelected:a},dislike:{count:d,isSelected:a}},user:{id:55689,name:"Ilya Shevelev",avatar:{original:"https:\u002F\u002Flh3.googleusercontent.com\u002Fa\u002FAItbvmm6b5HUpyCiGXQfH3U2yPqWGB45I0KN2QjbjYz6=s96-c",alt:"Аватар пользователя Ilya Shevelev",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FHJBMoPxZoKDVgRpdOc2td_ZAxHQttNlOYtgyatcdxvY\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUl0YnZtbTZiNUhVcHlDaUdYUWZIM1UyeVBxV0dCNDVJMEtOMlFqYmpZejY9czk2LWM",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FDZ96_5pKl5Dtdm0HvNgBLTq7KauZ3IJdLn2WDwvJSb4\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUl0YnZtbTZiNUhVcHlDaUdYUWZIM1UyeVBxV0dCNDVJMEtOMlFqYmpZejY9czk2LWM",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2022-08-23T19:53:19.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]},{id:4042,content:"title хорошо бы закрыть",votes:{like:{count:q,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:30482,name:"annthehuman",avatar:b},date:"2021-08-02T20:01:15.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]},{id:9293,content:"В index.html нужно закрыть <title>",votes:{like:{count:d,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:73792,name:"Максим «lostskill» Виноградов",avatar:{original:"https:\u002F\u002Flh3.googleusercontent.com\u002Fa\u002FAEdFTp4Fua4Rl0gVUe5romftm3TqD2bebMWG6bkrYFpuZw=s96-c",alt:"Аватар пользователя Максим «lostskill» Виноградов",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FHOOsyEB63rXXyqgpvLE15p89jj5pVMGUMebFyXINz3w\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUVkRlRwNEZ1YTRSbDBnVlVlNXJvbWZ0bTNUcUQyYmViTVdHNmJrcllGcHVadz1zOTYtYw=",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FPzqldMtvsAzElOUkLmlwZsqWQOhAPjh10Ql4wZMfQYY\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUVkRlRwNEZ1YTRSbDBnVlVlNXJvbWZ0bTNUcUQyYmViTVdHNmJrcllGcHVadz1zOTYtYw=",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2023-02-17T08:49:44.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]},{id:8040,content:"Ошибка в пути файла для написания представлений, там должно быть Leads\u002Fviews.py, вместо django-react-app\u002Fviews.py",votes:{like:{count:d,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:60877,name:"Nechay-Nitsevich",avatar:b},date:"2022-11-20T18:34:23.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[{type:F,url:"https:\u002F\u002Fmedia.tproger.ru\u002Fuploads\u002F2022\u002F11\u002F4daed57d-cdf6-4fbd-be06-e20a3eafe4d2.png"}],company:b,children:[]},{id:5990,content:"\"Добавьте в файл django_react\u002Fviews.py следующий код: {Глава \"Создаём представления\"}Точно ли имеется ввиду в этом фрагменте именно приложение \"django_react\", а не \"leads\". А то по всей видимости данный кусок должен именно в его представлении оказаться.",votes:{like:{count:d,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:o,name:p,avatar:b},date:"2022-01-05T20:26:07.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[{id:5991,content:"Да, точно так, я проверил в оригинале.Увольняйте копирайтера из Скиллбокс",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:o,name:p,avatar:b},parentUser:{id:o,name:p},date:"2022-01-05T20:31:36.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]}]},{id:45,content:"Я вообще не понял куда-что устанавливают это отдельный сервер надо?, куда писать команды..",votes:{like:{count:d,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:G,name:H,avatar:{original:"https:\u002F\u002Favatars.yandex.net\u002Fget-yapic\u002F20706\u002Fenc-01ff31ee99b42b3505b64a7aa9868fdb98eee9008467e0d4eb455d6405be2647\u002Fislands-200",alt:"Аватар пользователя VladimirKindyuk",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002F2DtDIK4Ex3P7gNFOw1pLwEruCJEactR0PfQuQs-7RGY\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9hdmF0YXJzLnlhbmRleC5uZXQvZ2V0LXlhcGljLzIwNzA2L2VuYy0wMWZmMzFlZTk5YjQyYjM1MDViNjRhN2FhOTg2OGZkYjk4ZWVlOTAwODQ2N2UwZDRlYjQ1NWQ2NDA1YmUyNjQ3L2lzbGFuZHMtMjAw",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002F0dtW8Obf5WhetTdK3TuWqWev4yEkXyy37LxxN5NIuN8\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9hdmF0YXJzLnlhbmRleC5uZXQvZ2V0LXlhcGljLzIwNzA2L2VuYy0wMWZmMzFlZTk5YjQyYjM1MDViNjRhN2FhOTg2OGZkYjk4ZWVlOTAwODQ2N2UwZDRlYjQ1NWQ2NDA1YmUyNjQ3L2lzbGFuZHMtMjAw",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2020-10-20T19:43:10.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[{id:245,content:"В статье приведены команды терминала для Linux\u002FMac. Это может быть либо отдельный сервер, либо локальная машина.",votes:{like:{count:d,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:r,name:s,avatar:{original:t,alt:u,dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:v,dpr:d,width:c},{url:w,dpr:d,width:h}],sizes:[{media:i,size:j}]}}},parentUser:{id:G,name:H},date:"2020-10-28T15:46:36.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]}]},{id:6360,content:"Подскажите, пожалуйста, почему приложение leads подключенно в INSTALLED_APPS с указанием конфигурационного файла, а приложение frontend - без? Есть ли, какая-то значимая разница между этими двумя способами?\u003Cdiv\u003EСпасибо, кстати, за статью.\u003C\u002Fdiv\u003E",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:45044,name:"zm412 Т.U.",avatar:{original:"https:\u002F\u002Flh3.googleusercontent.com\u002Fa\u002FAATXAJy9hwBsKw2qu4hWBRYlS7guFFIRIaOUULVQlqLF=s96-c",alt:"Аватар пользователя zm412 Т.U.",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FaDiZpYO51W_1hVs0S0-zB_9O0AsHL193Ky4OOr9rHPE\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKeTlod0JzS3cycXU0aFdCUllsUzdndUZGSVJJYU9VVUxWUWxxTEY9czk2LWM",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002Fw1_Huzbc1mm0ZjznFOw4s6-5PNgRd_EsKZl4obPdhFk\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKeTlod0JzS3cycXU0aFdCUllsUzdndUZGSVJJYU9VVUxWUWxxTEY9czk2LWM",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2022-02-19T20:23:52.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]},{id:2380,content:"Перечитайте оригинал https:\u002F\u002Fwww.valentinog.com\u002Fblog\u002Fdrf\u002F, там кое-что изменилось, и эта статья стала неактуальной",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:26768,name:"Даниил Ощепков",avatar:{original:"https:\u002F\u002Flh4.googleusercontent.com\u002F-Pq1LV2hBrqw\u002FAAAAAAAAAAI\u002FAAAAAAAAAAA\u002FAMZuuckk94BALaXDgKDXZzLs6QuO9ttC8g\u002Fs96-c\u002Fphoto.jpg",alt:"Аватар пользователя Даниил Ощепков",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002F1W3VRHjADkVTjzW_ScZkVjS0Mjt-Qre1FOZ9FGfP7ro\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDQuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1QcTFMVjJoQnJxdy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNrazk0QkFMYVhEZ0tEWFp6THM2UXVPOXR0QzhnL3M5Ni1jL3Bob3RvLmpwZw=",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FKQsOCQ97REHVuGSIsSEy1ygTzFrx2YjpBwUvUpsPEvc\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDQuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1QcTFMVjJoQnJxdy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNrazk0QkFMYVhEZ0tEWFp6THM2UXVPOXR0QzhnL3M5Ni1jL3Bob3RvLmpwZw=",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2021-04-27T02:10:22.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]},{id:779,content:"При загрузке статических файлов выходит ошибка:\n\"GET \u002Fstatic\u002Ffrontend\u002Fmain.js HTTP\u002F1.1\" 404",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:I,name:J,avatar:{original:"https:\u002F\u002Fmedia.tproger.ru\u002Fuser-uploads\u002F13428\u002Favatar.jpeg",alt:"Аватар пользователя Thr0TT1e",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FbTRp1Atkip_q3SOyGWoNHpKd_Mv_BXCsU7Hg86a4FWE\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9tZWRpYS50cHJvZ2VyLnJ1L3VzZXItdXBsb2Fkcy8xMzQyOC9hdmF0YXIuanBlZw=",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002Fz-UqjV4--K6-fY0uwmUw_NDejtnVhqEtYOD-SO70beU\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9tZWRpYS50cHJvZ2VyLnJ1L3VzZXItdXBsb2Fkcy8xMzQyOC9hdmF0YXIuanBlZw=",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2021-04-21T16:04:08.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[{id:10482,content:"вместо \u003Cbr \u002F\u003Esrc=\"{% static 'frontend\u002Fmain.js' %}\" \u003Cbr \u002F\u003Eв index.html нужно \u003Cbr \u002F\u003Esrc=\"{% static 'frontend\u002Fmain.js\u002Fmain.js' %}\"",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:71493,name:l,avatar:{original:"https:\u002F\u002Fmedia.tproger.ru\u002Fuser-uploads\u002F71493\u002Favatar.png",alt:"Аватар пользователя ",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FJ5_ML0XdDawamY5Kwt1yinoBhDpmoFq7QkOhp4U5QVs\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9tZWRpYS50cHJvZ2VyLnJ1L3VzZXItdXBsb2Fkcy83MTQ5My9hdmF0YXIucG5n",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FlQLB4v0oGn04qrmoUsWNiCH-_3AUu2E_Fo4M1tLhIkg\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9tZWRpYS50cHJvZ2VyLnJ1L3VzZXItdXBsb2Fkcy83MTQ5My9hdmF0YXIucG5n",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},parentUser:{id:I,name:J},date:"2023-05-29T16:52:15.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[{type:F,url:"https:\u002F\u002Fmedia.tproger.ru\u002Fuploads\u002F2023\u002F05\u002F811e7fb0-dcec-463b-bf3a-11d15ea7a31b.png"}],company:b,children:[]}]},{id:242,content:"Здраствуйте!\nВ разделе Создаём представления внизу код на какой файл надо поставить?",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:K,name:L,avatar:{original:"https:\u002F\u002Flh3.googleusercontent.com\u002F-QNUgLFp1Fjc\u002FAAAAAAAAAAI\u002FAAAAAAAAAAA\u002FAMZuucmCRUfECGh9O7yWUn7XdlwWgDH4Bg\u002Fs96-c\u002Fphoto.jpg",alt:"Аватар пользователя Qwerty_ Tv",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FPjXNC6IXBFvlZ72N_PntMONE71exHSRXablNMtDFX6k\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1RTlVnTEZwMUZqYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNtQ1JVZkVDR2g5Tzd5V1VuN1hkbHdXZ0RINEJnL3M5Ni1jL3Bob3RvLmpwZw=",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FwVMRfurah1U_koOJGQsJCY4Gx8Pg2fn1XF1qE1AFxlc\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1RTlVnTEZwMUZqYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNtQ1JVZkVDR2g5Tzd5V1VuN1hkbHdXZ0RINEJnL3M5Ni1jL3Bob3RvLmpwZw=",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2020-10-28T09:27:28.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[{id:236,content:"Здравствуйте. Представления - это views. Файл views.py, добавили в статью уточнение, спасибо.",votes:{like:{count:d,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:r,name:s,avatar:{original:t,alt:u,dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:v,dpr:d,width:c},{url:w,dpr:d,width:h}],sizes:[{media:i,size:j}]}}},parentUser:{id:K,name:L},date:"2020-10-28T15:51:41.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]}]},{id:624,content:"I had to add\nimport React, { Component } from \"react\";\nto the beginning of App.js\nto avoid \"Component is not defined\" error",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:M,name:N,avatar:{original:"https:\u002F\u002Flh6.googleusercontent.com\u002F-BYl60H4QXMM\u002FAAAAAAAAAAI\u002FAAAAAAAAAAA\u002FAMZuucnz0oLsEkSmFZhEAx4kXyX3lGIdrw\u002Fphoto.jpg",alt:"Аватар пользователя rtg experiments",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FcwLXYk1oJMCR9J8EhPYIkMSWwc91w15twrS393UIIHQ\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDYuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1CWWw2MEg0UVhNTS9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNuejBvTHNFa1NtRlpoRUF4NGtYeVgzbEdJZHJ3L3Bob3RvLmpwZw=",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FhotHYM839PEQ-MBvu8dLEa9TQvWoTDG1M75dPd_qunI\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDYuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1CWWw2MEg0UVhNTS9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNuejBvTHNFa1NtRlpoRUF4NGtYeVgzbEdJZHJ3L3Bob3RvLmpwZw=",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2020-09-16T08:48:52.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[{id:232,content:"Thx, fixed",votes:{like:{count:d,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:r,name:s,avatar:{original:t,alt:u,dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:v,dpr:d,width:c},{url:w,dpr:d,width:h}],sizes:[{media:i,size:j}]}}},parentUser:{id:M,name:N},date:"2020-10-28T15:48:27.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]}]},{id:500,content:".babelrc - файл для настройки Babel, туда\n{\n    \"presets\": [\n        \"@babel\u002Fpreset-env\", \"@babel\u002Fpreset-react\"\n    ]\n}",votes:{like:{count:e,isSelected:a},dislike:{count:e,isSelected:a}},user:{id:12836,name:"Alexandr Vorobev",avatar:{original:"https:\u002F\u002Flh3.googleusercontent.com\u002F-pBzJ3Wt8lJc\u002FAAAAAAAAAAI\u002FAAAAAAAAAAA\u002FAMZuucng9unN7LWNmkjhBHxbzz3LpsvAzA\u002Fphoto.jpg",alt:"Аватар пользователя Alexandr Vorobev",dimensions:{width:c,height:c},additionalSizes:{srcSet:[{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FK0MevyS8oYE9DfpHXQc3-vzFEVY99adHsnqZoOkEcQw\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1wQnpKM1d0OGxKYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNuZzl1bk43TFdObWtqaEJIeGJ6ejNMcHN2QXpBL3Bob3RvLmpwZw=",dpr:d,width:c},{url:"https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FArr1E8g5vG22eLP-6dM29xbLX2l6s_BrRLCh-Kani7w\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1wQnpKM1d0OGxKYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNuZzl1bk43TFdObWtqaEJIeGJ6ejNMcHN2QXpBL3Bob3RvLmpwZw=",dpr:d,width:h}],sizes:[{media:i,size:j}]}}},date:"2020-09-11T10:23:49.000+03:00",isDeleted:a,deleteStatus:f,isPin:a,media:[],company:b,children:[]}]},"/v1/auth/company{\"key\":\"/v1/auth/company: \"}":b},state:{},_errors:{"/v1/options{\"method\":\"GET\",\"query\":{\"link\":\"L3RyYW5zbGF0aW9ucy9kamFuZ28tcmVhY3Qtd2ViYXBw\"}}":b,"/v1/post/single/{\"method\":\"GET\",\"params\":{\"name\":\"django-react-webapp\",\"tag\":\"translations\"}}":b,"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/translations/test-driven-development-is-dumb/\"}}":b,"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/experts/estimate-programmers-competence-with-several-questions/\"}}":b,"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/translations/web-frameworks-how-to-get-started/\"}}":b,"/v1/embed/get{\"params\":{\"link\":\"https://tproger.ru/translations/concepts-to-become-an-advanced-react-developer/\"}}":b,"/v1/comments/post/128591{\"lazy\":true}":b,"/v1/auth/company{\"key\":\"/v1/auth/company: \"}":{message:"[GET] \"https:\u002F\u002Ftproger.ru\u002Fwp-node\u002Fv1\u002Fauth\u002Fcompany\": 401 Unauthorized",statusCode:401,statusMessage:"Unauthorized",data:{status:a,message:"E_UNAUTHORIZED: You are not authorized"}}},serverRendered:g,path:"\u002Ftranslations\u002Fdjango-react-webapp",pinia:{user:{auth:a,user:b,company:b,token:l,authModelOpen:a,authCallbacks:[],settingsMode:a,authPlace:"other"},options:{isShowAd:g,availableListokPositions:x},notifications:{notifications:[]},modals:{isShowModalBugReport:a},subscriptions:{loaded:a,subscriptions:[],subscriptionsView:[],countSubscriptions:b,page:d,perPage:18,isFirst:g,isCropped:a},posts:{feeds:{},posts:{},postsPortions:{},isLoadPortion:{},isMainLoading:{},isError:{},feedRequestInfo:{}},widgets:{widgets:{},widgetsOptions:{RightSidebar:{entityId:k,widgetOptions:{recommended_posts:{slug:O}}},PostFooter:{entityId:k,widgetOptions:{recommended_posts:{slug:O}}}},firstLoaded:g,resolver:b,entityId:k,subEntityId:b,entityIdIsChanged:a,subEntityIdIsChanged:a,loadingProgress:a}},config:{public:{IS_PROD:g,SENTRY_CLIENT_DNS:"https:\u002F\u002F5878ab4ef73649a6a0584650f853dad0@o413944.ingest.sentry.io\u002F4504649713385472",ENV:l,API_BACKEND_BASE_URL:P,API_FRONT_BASE_URL:P,API_QUIZ_BASE_URL:"https:\u002F\u002Ftproger.ru\u002Ftp-quiz\u002Fapi\u002F",AUTH_TELEGRAM_CALLBACK:l,SOCIAL_VK_MAIN:"https:\u002F\u002Fvk.com\u002Ftproger",SOCIAL_VK_WEB:"https:\u002F\u002Fvk.com\u002Ftproger_web",SOCIAL_VK_TNULL:"https:\u002F\u002Fvk.com\u002Ftnull",SOCIAL_ZEN_MAIN:"https:\u002F\u002Fzen.yandex.ru\u002Ftproger",SOCIAL_TWITTER_MAIN:"https:\u002F\u002Ftwitter.com\u002Ftproger",SOCIAL_TELEGRAM_MAIN:"https:\u002F\u002Ft.me\u002F+ANGj_G5y1AE3YjFi",ANALYTIC_SEND:g,ANALYTIC_DEBUG:a,WIDGET_TELEGRAM_MAIN:"https:\u002F\u002Ft.me\u002F+LpLVNzPUnmNkMmZi",SHORTCODE_URL:"https:\u002F\u002Ftproger.ru\u002Fiframe-loader\u002F",siteUrl:"https:\u002F\u002Ftproger.ru",ANALYTICS_ENABLE:a,SPECIALS_STATIC_URL:"https:\u002F\u002Fspecials.tproger.ru",device:{enabled:g,defaultUserAgent:"Mozilla\u002F5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F64.0.3282.39 Safari\u002F537.36",refreshOnResize:a},vk:{cdnURL:"https:\u002F\u002Fproxy.tproger.ru\u002Fvk-openapi.js",id:"VK-RTRG-271723-bcLdk"},ym:{noscript:g,cdnURL:"https:\u002F\u002Fproxy.tproger.ru\u002Fyandex-metrika.js",initParams:{defer:g,clickmap:g,trackLinks:g,accurateTrackBounce:g,webvisor:a,ecommerce:g},id:"27485085"}},app:{baseURL:"\u002F",buildAssetsDir:"\u002F_nuxt\u002F",cdnURL:l}}}}(false,null,48,1,0,"none",true,96,"(min-width: 0px)","48px","post","","tproger.ru","tproger",42557,"Alex undefined",2,6099,"Андрей Селивестров","https:\u002F\u002Flh4.googleusercontent.com\u002F-Lo8Z_LDX_3c\u002FAAAAAAAAAAI\u002FAAAAAAAAAAA\u002FAMZuucngerFgNgfClHnoxxRzxedy_Fn3Iw\u002Fs96-c\u002Fphoto.jpg","Аватар пользователя Андрей Селивестров","https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FnDEirrDHZnY7_hqELUXfEDU6CeWUme01kjqOQz-NeJw\u002Frs:fill:48:48:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDQuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1MbzhaX0xEWF8zYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNuZ2VyRmdOZ2ZDbEhub3h4Unp4ZWR5X0ZuM0l3L3M5Ni1jL3Bob3RvLmpwZw=","https:\u002F\u002Ftproger.ru\u002Fsigned_image\u002FwfWYCVsmJJ-MZA7ykJX6cFrU772bMo_o4pFKHYrWEOo\u002Frs:fill:96:96:true\u002Fcb:vimg_1\u002Ff:webp\u002FaHR0cHM6Ly9saDQuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1MbzhaX0xEWF8zYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BTVp1dWNuZ2VyRmdOZ2ZDbEhub3h4Unp4ZWR5X0ZuM0l3L3M5Ni1jL3Bob3RvLmpwZw=",Array(4),"#","Напишем приложение с бэкендом на Django и фронтендом на React. Создаём REST API на Джанго, добавляем React и соединяем в один проект.",20,4,5,25748,"HarleyK1ng","png",13868,"VladimirKindyuk",13428,"Thr0TT1e",14054,"Qwerty_ Tv",12968,"rtg experiments","django-react-webapp","https:\u002F\u002Ftproger.ru\u002Fwp-node"))</script>
<script src="https://proxy.tproger.ru/vk-openapi.js" defer></script>
<script type="application/ld+json" id="schema-org-graph" data-hid="3437552">{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@id": "https://tproger.ru/#website",
      "@type": "WebSite",
      "name": "Tproger",
      "url": "https://tproger.ru",
      "publisher": {
        "@id": "https://tproger.ru/#identity"
      }
    },
    {
      "@id": "https://tproger.ru/#identity",
      "@type": "Organization",
      "email": "sales@tproger.ru",
      "name": "Tproger",
      "telephone": "+7 916 559-71-10",
      "url": "https://tproger.ru",
      "address": {
        "@type": "PostalAddress",
        "postalCode": "129085",
        "addressCountry": "RU",
        "addressLocality": "Москва",
        "streetAddress": "Москва, Деловой Центр «Калибр»"
      },
      "image": {
        "@id": "https://tproger.ru/#/schema/image/0dc3723"
      },
      "logo": {
        "@id": "https://tproger.ru/#logo"
      }
    },
    {
      "@id": "https://tproger.ru/translations/django-react-webapp/#article",
      "@type": "Article",
      "description": "Напишем приложение с бэкендом на Django и фронтендом на React. Создаём REST API на Джанго, добавляем React и соединяем в один проект.",
      "headline": "Бэкенд на Django и фронтенд на React: пишем приложение",
      "author": {
        "@id": "https://tproger.ru/#identity"
      },
      "publisher": {
        "@id": "https://tproger.ru/#identity"
      }
    },
    {
      "@id": "https://tproger.ru/translations/django-react-webapp/#breadcrumb",
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "name": "Главная",
          "item": "https://tproger.ru",
          "position": 1
        },
        {
          "@type": "ListItem",
          "name": "Статьи",
          "item": "https://tproger.ru/articles",
          "position": 2
        },
        {
          "@type": "ListItem",
          "name": "Пишем приложение с бэкендом на Django и фронтендом на React",
          "position": 3
        }
      ]
    },
    {
      "@id": "https://tproger.ru/#/schema/image/0dc3723",
      "@type": "ImageObject",
      "contentUrl": "https://cdn.tproger.ru/android-chrome-32x32.png",
      "url": "https://cdn.tproger.ru/android-chrome-32x32.png"
    },
    {
      "@id": "https://tproger.ru/#logo",
      "@type": "ImageObject",
      "caption": "Tproger",
      "contentUrl": "https://cdn.tproger.ru/android-chrome-32x32.png",
      "height": 32,
      "url": "https://cdn.tproger.ru/android-chrome-32x32.png",
      "width": 32
    }
  ]
}</script></body>
</html>