Автор выбралOpen Sourcing Mental Illness Ltd для получения пожертвования в рамках программыWrite for DOnations.
Вступление
Люди используют разные типы устройств для подключения к Интернету и просмотра веб-страниц. Из-за этого приложения должны быть доступны из разных мест. Для традиционных веб-сайтов обычно достаточно адаптивного пользовательского интерфейса, но более сложные приложения часто требуют использования других методов и архитектур. К ним относятся наличие отдельных внутренних и внешних приложений REST, которые могут быть реализованы в виде клиентских веб-приложений, Progressive Web Apps (PWA) или собственных мобильных приложений.
Некоторые инструменты, которые вы можете использовать при создании более сложных приложений:
-
React, фреймворк JavaScript, который позволяет разработчикам создавать веб-интерфейсы и собственные интерфейсы для своих серверных программ REST API.
-
Django, бесплатная веб-платформа Python с открытым исходным кодом, которая следует архитектурному шаблону программного обеспеченияmodel view controller (MVC).
-
Django REST framework, мощный и гибкий набор инструментов для создания REST API в Django.
В этом руководстве вы создадите современное веб-приложение с отдельным интерфейсом и интерфейсом REST API с использованием React, Django и Django REST Framework. Используя React с Django, вы сможете воспользоваться последними достижениями в области JavaScript и внешней разработки. Вместо создания приложения Django, использующего встроенный шаблонизатор, вы будете использовать React в качестве библиотеки пользовательского интерфейса, используя преимущества своей виртуальной объектной модели документов (DOM), декларативного подхода и компонентов, которые быстро отображают изменения в данных.
Веб-приложение, которое вы создадите, хранит записи о клиентах в базе данных, и вы можете использовать его в качестве отправной точки для приложения CRM. Когда вы закончите, вы сможете создавать, читать, обновлять и удалять записи, используя интерфейс React со стилемBootstrap 4.
Предпосылки
Для завершения этого урока вам понадобится:
-
Машина для разработки с Ubuntu 18.04.
-
Python 3,
pipиvenvустановлены на вашем компьютере, выполнив шаги 1 и 2 изHow To Install Python 3 and Set Up a Local Programming Environment on Ubuntu 18.04. -
Node.js 6+ and
npm5.2 or higher installed on your machine. Вы можете установить их оба, следуя инструкциям вHow To Install Node.js on Ubuntu 18.04 по установке из PPA.
[[step-1 -—- create-a-python-virtual-environment-and-install-dependencies]] == Шаг 1. Создание виртуальной среды Python и установка зависимостей
На этом этапе мы создадим виртуальную среду и установим необходимые зависимости для нашего приложения, включая Django, структуру Django REST иdjango-cors-headers.
Наше приложение будет использовать два разных сервера разработки для Django и React. Они будут работать на разных портах и будут функционировать как два отдельных домена. Из-за этого нам нужно включитьcross-origin resource sharing (CORS) для отправки HTTP-запросов из React в Django без блокировки браузером.
Перейдите в свой домашний каталог и создайте виртуальную среду, используя модуль Python 3venv:
cd ~
python3 -m venv ./env
Активируйте созданную виртуальную среду с помощьюsource:
source env/bin/activate
Затем установите зависимости проекта с помощьюpip. Они будут включать в себя:
-
Django: Веб-фреймворк для проекта.
-
Django REST framework: стороннее приложение, которое создает REST API с помощью Django.
-
django-cors-headers: пакет, который включает CORS.
Установите фреймворк Django:
pip install django djangorestframework django-cors-headers
Установив зависимости проекта, вы можете создать проект Django и интерфейс React.
[[step-2 -—- created-the-django-project]] == Шаг 2 - Создание проекта Django
На этом этапе мы сгенерируем проект Django, используя следующие команды и утилиты:
-
django-admin startproject project-name:django-admin- это утилита командной строки, используемая для выполнения задач с Django. Командаstartprojectсоздает новый проект Django. -
python manage.py startapp myapp:manage.py- служебный сценарий, автоматически добавляемый в каждый проект Django, который выполняет ряд административных задач: создание новых приложений, перенос базы данных и локальное обслуживание проекта Django. Его командаstartappсоздает приложение Django внутри проекта Django. В Django терминapplication описывает пакет Python, который предоставляет некоторый набор функций в проекте.
Для начала создайте проект Django сdjango-admin startproject. Назовем наш проектdjangoreactproject:
django-admin startproject djangoreactproject
Прежде чем двигаться дальше, давайте посмотрим на структуру каталогов нашего проекта Django с помощью командыtree.
[.Примечание]##
Tip:tree - полезная команда для просмотра структур файлов и каталогов из командной строки. Вы можете установить его с помощью следующей команды:
sudo apt-get install tree
Чтобы использовать его, введитеcd в нужный каталог и введитеtree или укажите путь к начальной точке с помощьюtree /home/sammy/sammys-project.
Перейдите в папкуdjangoreactproject в корне вашего проекта и выполните командуtree:
cd ~/djangoreactproject
tree
Вы увидите следующий вывод:
Output├── djangoreactproject
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
Папка~/djangoreactproject является корнем проекта. В этой папке есть несколько файлов, которые будут важны для вашей работы:
-
manage.py: служебный сценарий, выполняющий ряд административных задач. -
settings.py: основной файл конфигурации для проекта Django, в котором вы можете изменять настройки проекта. Эти параметры включают такие переменные, какINSTALLED_APPS, alist строк, обозначающих включенные приложения для вашего проекта. В документации Django есть дополнительная информация оavailable settings. -
urls.py: этот файл содержит список шаблонов URL и связанных представлений. Каждый шаблон отображает связь между URL-адресом и функцией, которая должна вызываться для этого URL-адреса. Дополнительные сведения об URL-адресах и представлениях см. В нашем руководстве поHow To Create Django Views.
Нашим первым шагом в работе с проектом будет настройка пакетов, которые мы установили на предыдущем шаге, включая структуру Django REST и пакет Django CORS, путем добавления их вsettings.py. Откройте файл с помощьюnano или вашего любимого редактора:
nano ~/djangoreactproject/djangoreactproject/settings.py
Перейдите к настройкеINSTALLED_APPS и добавьте приложенияrest_framework иcorsheaders в конец списка:
~/djangoreactproject/djangoreactproject/settings.py
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders'
]
Затем добавьте промежуточное ПОcorsheaders.middleware.CorsMiddleware из ранее установленного пакета CORS в параметрMIDDLEWARE. Этот параметр представляет собой списокmiddlewares, класса Python, который содержит код, обрабатываемый каждый раз, когда ваше веб-приложение обрабатывает запрос или ответ:
~/djangoreactproject/djangoreactproject/settings.py
...
MIDDLEWARE = [
...
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware'
]
Далее вы можете включить CORS. ПараметрCORS_ORIGIN_ALLOW_ALL указывает, хотите ли вы разрешить CORS для всех доменов, аCORS_ORIGIN_WHITELIST - это кортеж Python, содержащий разрешенные URL-адреса. В нашем случае, поскольку сервер разработки React будет работать наhttp://localhost:3000, мы добавим новые настройкиCORS_ORIGIN_ALLOW_ALL = False иCORS_ORIGIN_WHITELIST('localhost:3000',) в наш файлsettings.py. Добавьте эти параметры в любое место файла:
~/djangoreactproject/djangoreactproject/settings.py
...
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'localhost:3000',
)
...
Вы можете найти больше параметров конфигурации вdjango-cors-headers docs.
Сохраните файл и выйдите из редактора, когда закончите.
По-прежнему в каталоге~/djangoreactproject создайте новое приложение Django с именемcustomers:
python manage.py startapp customers
Он будет содержатьmodels иviews для управления клиентами. Модели определяют поля и поведение данных нашего приложения, а представления позволяют нашему приложению правильно обрабатывать веб-запросы и возвращать требуемые ответы.
Затем добавьте это приложение в список установленных приложений в файлеsettings.py вашего проекта, чтобы Django распознал его как часть проекта. Снова откройтеsettings.py:
nano ~/djangoreactproject/djangoreactproject/settings.py
Добавьте приложениеcustomers:
~/djangoreactproject/djangoreactproject/settings.py
...
INSTALLED_APPS = [
...
'rest_framework',
'corsheaders',
'customers'
]
...
Затемmigrate база данных и запуск локального сервера разработки. Migrations - это способ Django распространять изменения, которые вы вносите в свои модели, в схему базы данных. Эти изменения могут включать, например, добавление поля или удаление модели. Подробнее о моделях и миграции см.How To Create Django Models.
Перенос базы данных:
python manage.py migrate
Запустите локальный сервер разработки:
python manage.py runserver
Вы увидите вывод, похожий на следующий:
OutputPerforming system checks...
System check identified no issues (0 silenced).
October 22, 2018 - 15:14:50
Django version 2.1.2, using settings 'djangoreactproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Ваше веб-приложение будет запущено сhttp://127.0.0.1:8000. Если вы перейдете по этому адресу в вашем веб-браузере, вы должны увидеть следующую страницу:

На этом этапе оставьте приложение запущенным и откройте новый терминал, чтобы продолжить разработку проекта.
[[step-3 -—- Creating-the-react-frontend]] == Шаг 3 - Создание React Frontend
В этом разделе мы собираемся создать интерфейсное приложение нашего проекта с использованием React.
В React есть официальная утилита, которая позволяет быстро создавать проекты React без необходимости напрямую настраиватьWebpack. Webpack - это пакет модулей, используемый для объединения веб-ресурсов, таких как код JavaScript, CSS и изображения. Обычно, прежде чем вы сможете использовать Webpack, вам необходимо установить различные параметры конфигурации, но благодаря утилитеcreate-react-app вам не придется иметь дело с Webpack напрямую, пока вы не решите, что вам нужно больше контроля. Для запускаcreate-react-app вы можете использоватьnpx, инструмент, который выполняет двоичные файлы пакетаnpm.
Во втором терминале убедитесь, что вы находитесь в каталоге вашего проекта:
cd ~/djangoreactproject
Создайте проект React с именемfrontend, используяcreate-react-app иnpx:
npx create-react-app frontend
Затем перейдите в приложение React и запустите сервер разработки:
cd ~/djangoreactproject/frontend
npm start
Ваше приложение будет запущено сhttp://localhost:3000/:

Оставьте сервер разработки React работающим и откройте другое окно терминала, чтобы продолжить.
Чтобы увидеть структуру каталогов всего проекта на этом этапе, перейдите в корневую папку и снова запуститеtree:
cd ~/djangoreactproject
tree
Вы увидите такую структуру:
Output├── customers
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── djangoreactproject
│ ├── __init__.py
│ ├── __pycache__
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── frontend
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ ├── README.md
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── registerServiceWorker.js
│ └── yarn.lock
└── manage.py
Наше приложение будет использовать Bootstrap 4 для стилизации интерфейса React, поэтому мы включим его в файлfrontend/src/App.css, который управляет нашими настройками CSS. Откройте файл:
nano ~/djangoreactproject/frontend/src/App.css
Добавьте следующиеimport в начало файла. Вы можете удалить существующее содержимое файла, хотя это не обязательно:
~/djangoreactproject/frontend/src/App.css
@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
Здесь@import - это инструкция CSS, которая используется для импорта правил стилей из других таблиц стилей.
Теперь, когда мы создали как внутренние, так и внешние приложения, давайте создадим модель Customer и некоторые демонстрационные данные.
[[step-4 -—- Creating-the-customer-model-and-initial-data]] == Шаг 4 - Создание модели клиента и исходных данных
После создания приложения Django и внешнего интерфейса React наш следующий шаг - создание модели Customer, представляющей таблицу базы данных, в которой будет храниться информация о клиентах. Вам не нужен SQL, поскольку DjangoObject Relational Mapper (ORM) будет обрабатывать операции с базой данных, отображая классы и переменные Python в таблицы и столбцы SQL. Таким образом, Django ORM абстрагирует взаимодействия SQL с базой данных через интерфейс Python.
Активируйте вашу виртуальную среду снова:
cd ~
source env/bin/activate
Перейдите в каталогcustomers и откройтеmodels.py, файл Python, содержащий модели вашего приложения:
cd ~/djangoreactproject/customers/
nano models.py
Файл будет содержать следующее содержимое:
~/djangoreactproject/customers/models.py
from django.db import models
# Create your models here.
API модели клиента уже импортирован в файл благодаря оператору импортаfrom django.db import models. Теперь вы добавите классCustomer, который расширяетmodels.Model. Каждая модель в Django - это класс Python, расширяющийdjango.db.models.Model.
МодельCustomer будет иметь следующие поля базы данных:
-
first_name- Имя покупателя. -
last_name- Фамилия покупателя. -
email- адрес электронной почты покупателя. -
phone- Номер телефона покупателя. -
address- Адрес покупателя. -
description- Описание заказчика. -
createdAt- Дата добавления покупателя.
Мы также добавим функцию__str__(), которая определяет, как будет отображаться модель. В нашем случае это будет имя клиента. Подробнее о создании классов и определении объектов см.How To Construct Classes and Define Objects in Python 3.
Добавьте следующий код в файл:
~/djangoreactproject/customers/models.py
from django.db import models
class Customer(models.Model):
first_name = models.CharField("First name", max_length=255)
last_name = models.CharField("Last name", max_length=255)
email = models.EmailField()
phone = models.CharField(max_length=20)
address = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
createdAt = models.DateTimeField("Created At", auto_now_add=True)
def __str__(self):
return self.first_name
Затем перенесите базу данных, чтобы создать таблицы базы данных. Командаmakemigrations создает файлы миграции, в которые будут добавлены изменения модели, аmigrate применяет изменения в файлах миграции к базе данных.
Вернитесь в корневую папку проекта:
cd ~/djangoreactproject
Выполните следующее для создания файлов миграции:
python manage.py makemigrations
Вы получите вывод, который выглядит следующим образом:
Outputcustomers/migrations/0001_initial.py
- Create model Customer
Примените эти изменения к базе данных:
python manage.py migrate
Вы увидите вывод, указывающий на успешную миграцию:
OutputOperations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0001_initial... OK
Затем вы будете использоватьdata migration file для создания исходных данных о клиенте. data migration file - это миграция, которая добавляет или изменяет данные в базе данных. Создайте пустой файл миграции данных для приложенияcustomers:
python manage.py makemigrations --empty --name customers customers
Вы увидите следующее подтверждение с именем вашего файла миграции:
OutputMigrations for 'customers':
customers/migrations/0002_customers.py
Обратите внимание, что имя вашего файла миграции0002_customers.py.
Затем перейдите в папку миграции приложенияcustomers:
cd ~/djangoreactproject/customers/migrations
Откройте созданный файл миграции:
nano 0002_customers.py
Это начальное содержимое файла:
~/djangoreactproject/customers/migrations/0002_customers.py
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('customers', '0001_initial'),
]
operations = [
]
Оператор импорта импортирует APImigrations, API Django для создания миграций, изdjango.db, встроенного пакета, который содержит классы для работы с базами данных.
КлассMigration - это класс Python, описывающий операции, выполняемые при миграции баз данных. Этот класс расширяетmigrations.Migration и имеет два списка:
-
dependencies: содержит зависимые миграции. -
operations: содержит операции, которые будут выполнены при применении миграции.
Затем добавьтеmethod, чтобы создать демонстрационные данные о клиентах. Добавьте следующий метод перед определением классаMigration:
~/djangoreactproject/customers/migrations/0002_customers.py
...
def create_data(apps, schema_editor):
Customer = apps.get_model('customers', 'Customer')
Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
...
В этом методе мы берем классCustomer нашего приложенияcustomers и создаем демонстрационного клиента для вставки в базу данных.
Чтобы получить классCustomer, который позволит создавать новых клиентов, мы используем методget_model() объектаapps. Объектapps представляетregistry установленных приложений и их моделей баз данных.
Объектapps будет передан из методаRunPython(), когда мы будем использовать его для запускаcreate_data(). Добавьте методmigrations.RunPython() в пустой списокoperations:
~/djangoreactproject/customers/migrations/0002_customers.py
...
operations = [
migrations.RunPython(create_data),
]
RunPython() - это часть Migrations API, позволяющая запускать собственный код Python при миграции. В нашем спискеoperations указано, что этот метод будет выполнен, когда мы применим миграцию.
Это полный файл:
~/djangoreactproject/customers/migrations/0002_customers.py
from django.db import migrations
def create_data(apps, schema_editor):
Customer = apps.get_model('customers', 'Customer')
Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
class Migration(migrations.Migration):
dependencies = [
('customers', '0001_initial'),
]
operations = [
migrations.RunPython(create_data),
]
Для получения дополнительной информации о миграции данных см. Документацию поdata migrations in Django
Чтобы перенести базу данных, сначала вернитесь в корневую папку вашего проекта:
cd ~/djangoreactproject
Перенесите базу данных, чтобы создать демонстрационные данные:
python manage.py migrate
Вы увидите вывод, который подтверждает миграцию:
OutputOperations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0002_customers... OK
Для получения дополнительных сведений об этом процессе обратитесь кHow To Create Django Models.
Создав модель Customer и демонстрационные данные, мы можем перейти к созданию REST API.
[[step-5 -—- Creating-the-rest-api]] == Шаг 5. Создание REST API
На этом шаге мы создадим REST API с использованием Django REST Framework. Мы создадим несколько разныхAPI views. Представление API - это функция, которая обрабатывает запрос или вызов API, аAPI endpoint - это уникальный URL-адрес, который представляет точку взаимодействия с системой REST. Например, когда пользователь отправляет запрос GET на конечную точку API, Django вызывает соответствующую функцию или представление API для обработки запроса и возврата любых возможных результатов.
Мы также будем использоватьserializers. serializer в Django REST Framework позволяет преобразовывать сложные экземпляры модели и QuerySets в формат JSON для использования API. Класс сериализатора также может работать в другом направлении, предоставляя механизмы для синтаксического анализа и десериализации данных в модели Django и QuerySets.
Наши конечные точки API будут включать:
-
api/customers: эта конечная точка используется для создания клиентов и возвращает разбитые на страницы наборы клиентов. -
api/customers/<pk>: эта конечная точка используется для получения, обновления и удаления отдельных клиентов по первичному ключу или идентификатору.
Мы также создадим URL-адреса в файле проектаurls.py для соответствующих конечных точек (например,api/customers иapi/customers/<pk>).
Начнем с созданияserializer class для нашей моделиCustomer.
Добавление класса сериализатора
Создание класса сериализатора для нашей моделиCustomer необходимо для преобразования экземпляров клиентов и QuerySet в JSON и обратно. Чтобы создать класс сериализатора, сначала создайте файлserializers.py внутри приложенияcustomers:
cd ~/djangoreactproject/customers/
nano serializers.py
Добавьте следующий код для импорта API сериализаторов и моделиCustomer:
~/djangoreactproject/customers/serializers.py
from rest_framework import serializers
from .models import Customer
Затем создайте класс сериализатора, который расширяетserializers.ModelSerializer и определяет поля, которые будут сериализованы:
~/djangoreactproject/customers/serializers.py
...
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
КлассMeta определяет модель и поля для сериализации:pk,first_name,last_name,email,phone,address ,description.
Это полное содержимое файла:
~/djangoreactproject/customers/serializers.py
from rest_framework import serializers
from .models import Customer
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
Теперь, когда мы создали наш класс сериализатора, мы можем добавить представления API.
Добавление представлений API
В этом разделе мы создадим представления API для нашего приложения, которые будут вызываться Django, когда пользователь посещает конечную точку, соответствующую функции представления.
Открыть~/djangoreactproject/customers/views.py:
nano ~/djangoreactproject/customers/views.py
Удалите то, что там, и добавьте следующий импорт:
~/djangoreactproject/customers/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Customer
from .serializers import *
Мы импортируем созданный сериализатор вместе с модельюCustomer и API-интерфейсами Django и Django REST Framework.
Затем добавьте представление для обработки запросов POST и GET HTTP:
~/djangoreactproject/customers/views.py
...
@api_view(['GET', 'POST'])
def customers_list(request):
"""
List customers, or create a new customer.
"""
if request.method == 'GET':
data = []
nextPage = 1
previousPage = 1
customers = Customer.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(customers, 10)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)
serializer = CustomerSerializer(data,context={'request': request} ,many=True)
if data.has_next():
nextPage = data.next_page_number()
if data.has_previous():
previousPage = data.previous_page_number()
return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
elif request.method == 'POST':
serializer = CustomerSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Сначала мы используем декоратор@api_view(['GET', 'POST']), чтобы создать представление API, которое может принимать запросы GET и POST. decorator - это функция, которая берет другую функцию и динамически ее расширяет.
В теле метода мы используем переменнуюrequest.method для проверки текущего HTTP-метода и выполнения соответствующей логики в зависимости от типа запроса:
-
Если это запрос GET, метод разбивает данные на страницы с помощью DjangoPaginator и возвращает первую страницу данных после сериализации, количество доступных клиентов, количество доступных страниц и ссылки на предыдущую и следующую страницы. . Paginator - это встроенный класс Django, который разбивает список данных на страницы и предоставляет методы для доступа к элементам для каждой страницы.
-
Если это запрос POST, метод сериализует полученные данные клиента, а затем вызывает метод
save()объекта сериализатора. Затем он возвращает объект Response, экземплярHttpResponse, с кодом состояния 201. Каждое созданное вами представление отвечает за сохранение объектаHttpResponse. Методsave()сохраняет сериализованные данные в базе данных.
Дополнительные сведения оHttpResponse и представлениях см. В этом обсужденииcreating view functions.
Теперь добавьте представление API, которое будет отвечать за обработку запросов GET, PUT и DELETE для получения, обновления и удаления клиентов поpk (первичный ключ):
~/djangoreactproject/customers/views.py
...
@api_view(['GET', 'PUT', 'DELETE'])
def customers_detail(request, pk):
"""
Retrieve, update or delete a customer by id/pk.
"""
try:
customer = Customer.objects.get(pk=pk)
except Customer.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = CustomerSerializer(customer,context={'request': request})
return Response(serializer.data)
elif request.method == 'PUT':
serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
customer.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Метод украшен символом@api_view(['GET', 'PUT', 'DELETE']), чтобы обозначить, что это представление API, которое может принимать запросы GET, PUT и DELETE.
Проверка в полеrequest.method проверяет метод запроса и в зависимости от его значения вызывает правильную логику:
-
Если это запрос GET, данные клиента сериализуются и отправляются с использованием объекта Response.
-
Если это запрос PUT, метод создает сериализатор для новых данных клиента. Затем он вызывает метод
save()созданного объекта сериализатора. Наконец, он отправляет объект Response обновленному клиенту. -
Если это запрос DELETE, метод вызывает метод
delete()объекта клиента для его удаления, а затем возвращает объект Response без данных.
Готовый файл выглядит так:
~/djangoreactproject/customers/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Customer
from .serializers import *
@api_view(['GET', 'POST'])
def customers_list(request):
"""
List customers, or create a new customer.
"""
if request.method == 'GET':
data = []
nextPage = 1
previousPage = 1
customers = Customer.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(customers, 5)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)
serializer = CustomerSerializer(data,context={'request': request} ,many=True)
if data.has_next():
nextPage = data.next_page_number()
if data.has_previous():
previousPage = data.previous_page_number()
return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
elif request.method == 'POST':
serializer = CustomerSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])
def customers_detail(request, pk):
"""
Retrieve, update or delete a customer by id/pk.
"""
try:
customer = Customer.objects.get(pk=pk)
except Customer.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = CustomerSerializer(customer,context={'request': request})
return Response(serializer.data)
elif request.method == 'PUT':
serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
customer.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Теперь мы можем перейти к созданию наших конечных точек.
Добавление конечных точек API
Теперь мы создадим конечные точки API:api/customers/ для запроса и создания клиентов иapi/customers/<pk> для получения, обновления или удаления отдельных клиентов по ихpk.
Открыть~/djangoreactproject/djangoreactproject/urls.py:
nano ~/djangoreactproject/djangoreactproject/urls.py
Оставьте то, что есть, но добавьте импорт в представленияcustomers вверху файла:
~/djangoreactproject/djangoreactproject/urls.py
from django.contrib import admin
from django.urls import path
from customers import views
from django.conf.urls import url
Затем добавьте URL-адресаapi/customers/ иapi/customers/<pk> кurlpatterns list, содержащему URL-адреса приложения:
~/djangoreactproject/djangoreactproject/urls.py
...
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^api/customers/$', views.customers_list),
url(r'^api/customers/(?P[0-9]+)$', views.customers_detail),
]
Создав наши конечные точки REST, давайте посмотрим, как мы можем их использовать.
[[step-6 -—- consuming-the-rest-api-with-axios]] == Шаг 6 - Использование REST API с Axios
На этом этапе мы установимAxios, HTTP-клиент, который мы будем использовать для вызовов API. Мы также создадим класс для использования конечных точек API, которые мы создали.
Во-первых, деактивируйте вашу виртуальную среду:
deactivate
Затем перейдите в папкуfrontend:
cd ~/djangoreactproject/frontend
Установитеaxios изnpm, используя:
npm install axios --save
Параметр--save добавляет зависимостьaxios к файлуpackage.json вашего приложения.
Затем создайте файл JavaScript с именемCustomersService.js, который будет содержать код для вызова REST API. Мы сделаем это внутри папкиsrc, где будет жить код приложения для нашего проекта:
cd src
nano CustomersService.js
Добавьте следующий код, который содержит методы для подключения к API REST Django:
~/djangoreactproject/frontend/src/CustomersService.js
import axios from 'axios';
const API_URL = 'http://localhost:8000';
export default class CustomersService{
constructor(){}
getCustomers() {
const url = `${API_URL}/api/customers/`;
return axios.get(url).then(response => response.data);
}
getCustomersByURL(link){
const url = `${API_URL}${link}`;
return axios.get(url).then(response => response.data);
}
getCustomer(pk) {
const url = `${API_URL}/api/customers/${pk}`;
return axios.get(url).then(response => response.data);
}
deleteCustomer(customer){
const url = `${API_URL}/api/customers/${customer.pk}`;
return axios.delete(url);
}
createCustomer(customer){
const url = `${API_URL}/api/customers/`;
return axios.post(url,customer);
}
updateCustomer(customer){
const url = `${API_URL}/api/customers/${customer.pk}`;
return axios.put(url,customer);
}
}
КлассCustomersService будет вызывать следующие методы Axios:
-
getCustomers(): получает первую страницу клиентов. -
getCustomersByURL(): получает клиентов по URL. Это позволяет переходить на следующие страницы клиентов, передавая такие ссылки, как/api/customers/?page=2. -
getCustomer(): получает клиента по первичному ключу. -
createCustomer(): создает клиента. -
updateCustomer(): обновляет клиента. -
deleteCustomer(): удаляет клиента.
Теперь мы можем отображать данные из нашего API в нашем интерфейсе React UI, создав компонентCustomersList.
[[step-7 -—- displaying-data-from-the-api-in-the-react-application]] == Шаг 7. Отображение данных из API в приложении React
На этом этапе мы создадимCustomersList Reactcomponent. Компонент React представляет собой часть пользовательского интерфейса; это также позволяет вам разделить пользовательский интерфейс на независимые, многократно используемые части.
Начнем с созданияCustomersList.js вfrontend/src:
nano ~/djangoreactproject/frontend/src/CustomersList.js
Начните с импортаReact иComponent, чтобы создать компонент React:
~/djangoreactproject/frontend/src/CustomersList.js
import React, { Component } from 'react';
Затем импортируйте и создайте экземпляр модуляCustomersService, который вы создали на предыдущем шаге, который предоставляет методы, которые взаимодействуют с серверной частью REST API:
~/djangoreactproject/frontend/src/CustomersList.js
...
import CustomersService from './CustomersService';
const customersService = new CustomersService();
Затем создайте компонентCustomersList, который расширяетComponent для вызова REST API. Компонент React долженextend or subclass the Component class. Дополнительные сведения о классах E6 и наследовании см. В нашем руководстве поUnderstanding Classes in JavaScript.
Добавьте следующий код, чтобы создать компонент React, расширяющийreact.Component:
~/djangoreactproject/frontend/src/CustomersList.js
...
class CustomersList extends Component {
constructor(props) {
super(props);
this.state = {
customers: [],
nextPageURL: ''
};
this.nextPage = this.nextPage.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
}
export default CustomersList;
Внутриconstructor мы инициализируем объектstate. Он содержит переменные состояния нашего компонента, используя пустойcustomersarray. Этот массив будет содержать клиентов иnextPageURL, которые будут содержать URL-адрес следующей страницы, которую нужно получить из внутреннего API. Мы такжеbindingnextPage() иhandleDelete()methods доthis, поэтому они будут доступны из HTML-кода.
Затем добавьте методcomponentDidMount() и вызовgetCustomers() в классеCustomersList перед закрывающей фигурной скобкой.
МетодcomponentDidMount() - это метод жизненного цикла компонента, который вызывается, когда компонент создается и вставляется в DOM. getCustomers() вызывает объект обслуживания клиентов, чтобы получить первую страницу данных и ссылку на следующую страницу из бэкэнда Django:
~/djangoreactproject/frontend/src/CustomersList.js
...
componentDidMount() {
var self = this;
customersService.getCustomers().then(function (result) {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
Теперь добавьте методhandleDelete(), который обрабатывает удаление клиента, нижеcomponentDidMount():
~/djangoreactproject/frontend/src/CustomersList.js
...
handleDelete(e,pk){
var self = this;
customersService.deleteCustomer({pk : pk}).then(()=>{
var newArr = self.state.customers.filter(function(obj) {
return obj.pk !== pk;
});
self.setState({customers: newArr})
});
}
МетодhandleDelete() вызывает методdeleteCustomer() для удаления клиента, используя егоpk (первичный ключ). Если операция прошла успешно, массивcustomers отфильтровывается для удаленного клиента.
Затем добавьте методnextPage(), чтобы получить данные для следующей страницы и обновить ссылку на следующую страницу:
~/djangoreactproject/frontend/src/CustomersList.js
...
nextPage(){
var self = this;
customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
МетодnextPage() вызывает методgetCustomersByURL(), который берет URL следующей страницы из объекта состоянияthis.state.nextPageURL и обновляет массивcustomers возвращенными данными.
Наконец, добавьте компонентrender() method, который отображает таблицу клиентов из состояния компонента:
~/djangoreactproject/frontend/src/CustomersList.js
...
render() {
return (
#
First Name
Last Name
Phone
Email
Address
Description
Actions
{this.state.customers.map( c =>
{c.pk}
{c.first_name}
{c.last_name}
{c.phone}
{c.email}
{c.address}
{c.description}
Update
)}
);
}
Это полное содержимое файла:
~/djangoreactproject/frontend/src/CustomersList.js
import React, { Component } from 'react';
import CustomersService from './CustomersService';
const customersService = new CustomersService();
class CustomersList extends Component {
constructor(props) {
super(props);
this.state = {
customers: [],
nextPageURL: ''
};
this.nextPage = this.nextPage.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
componentDidMount() {
var self = this;
customersService.getCustomers().then(function (result) {
console.log(result);
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
handleDelete(e,pk){
var self = this;
customersService.deleteCustomer({pk : pk}).then(()=>{
var newArr = self.state.customers.filter(function(obj) {
return obj.pk !== pk;
});
self.setState({customers: newArr})
});
}
nextPage(){
var self = this;
console.log(this.state.nextPageURL);
customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
render() {
return (
#
First Name
Last Name
Phone
Email
Address
Description
Actions
{this.state.customers.map( c =>
{c.pk}
{c.first_name}
{c.last_name}
{c.phone}
{c.email}
{c.address}
{c.description}
Update
)}
);
}
}
export default CustomersList;
Теперь, когда мы создали компонентCustomersList для отображения списка клиентов, мы можем добавить компонент, который обрабатывает создание и обновление клиентов.
[[step-8 -—- add-the-customer-create-and-update-react-component]] == Шаг 8 - Добавление компонента Customer Create и Update React
На этом этапе мы создадим компонентCustomerCreateUpdate, который будет обрабатывать создание и обновление клиентов. Это будет сделано путем предоставления формы, которую пользователи могут использовать для ввода данных о новом клиенте или обновления существующей записи.
Вfrontend/src создайте файлCustomerCreateUpdate.js:
nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
Добавьте следующий код для создания компонента React, импортирующегоReact иComponent:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
import React, { Component } from 'react';
Мы также можем импортировать и создать экземпляр классаCustomersService, который мы создали на предыдущем шаге, который предоставляет методы, взаимодействующие с серверной частью REST API:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
import CustomersService from './CustomersService';
const customersService = new CustomersService();
Затем создайте компонентCustomerCreateUpdate, который расширяетComponent для создания и обновления клиентов:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
}
}
export default CustomerCreateUpdate;
В определение класса добавьте методrender() компонента, который отображает HTML-форму, которая принимает информацию о клиенте:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
render() {
return (
);
}
Для каждого элемента ввода формы метод добавляет свойствоref для доступа и установки значения элемента формы.
Затем, над методомrender(), определите методhandleSubmit(event), чтобы у вас была правильная функциональность, когда пользователь нажимает кнопку отправки:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
handleSubmit(event) {
const { match: { params } } = this.props;
if(params && params.pk){
this.handleUpdate(params.pk);
}
else
{
this.handleCreate();
}
event.preventDefault();
}
...
МетодhandleSubmit(event) обрабатывает отправку формы и, в зависимости от маршрута, вызывает либо методhandleUpdate(pk), чтобы обновить клиента переданнымpk, либо методhandleCreate() для создания новый клиент. Мы определим эти методы в ближайшее время.
Вернувшись к конструктору компонента, привяжите недавно добавленный методhandleSubmit() кthis, чтобы вы могли получить к нему доступ в своей форме:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
...
Затем определите методhandleCreate() для создания клиента из данных формы. Над методомhandleSubmit(event) добавьте следующий код:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
handleCreate(){
customersService.createCustomer(
{
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}).then((result)=>{
alert("Customer created!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
...
МетодhandleCreate() будет использоваться для создания клиента из введенных данных. Он вызывает соответствующий методCustomersService.createCustomer(), который вызывает фактический вызов API в серверную часть для создания клиента.
Затем под методомhandleCreate() определите методhandleUpdate(pk) для реализации обновлений:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
handleUpdate(pk){
customersService.updateCustomer(
{
"pk": pk,
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}
).then((result)=>{
alert("Customer updated!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
МетодupdateCustomer() обновит клиента наpk, используя новую информацию из формы информации о клиенте. Он вызывает методcustomersService.updateCustomer().
Затем добавьте методcomponentDidMount(). Если пользователь посещает маршрутcustomer/:pk, мы хотим заполнить форму информацией, связанной с клиентом, используя первичный ключ из URL-адреса. Для этого мы можем добавить методgetCustomer(pk) после того, как компонент будет смонтирован в событии жизненного циклаcomponentDidMount(). Добавьте следующий код ниже конструктора компонента, чтобы добавить этот метод:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
componentDidMount(){
const { match: { params } } = this.props;
if(params && params.pk)
{
customersService.getCustomer(params.pk).then((c)=>{
this.refs.firstName.value = c.first_name;
this.refs.lastName.value = c.last_name;
this.refs.email.value = c.email;
this.refs.phone.value = c.phone;
this.refs.address.value = c.address;
this.refs.description.value = c.description;
})
}
}
Это полное содержимое файла:
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
import React, { Component } from 'react';
import CustomersService from './CustomersService';
const customersService = new CustomersService();
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount(){
const { match: { params } } = this.props;
if(params && params.pk)
{
customersService.getCustomer(params.pk).then((c)=>{
this.refs.firstName.value = c.first_name;
this.refs.lastName.value = c.last_name;
this.refs.email.value = c.email;
this.refs.phone.value = c.phone;
this.refs.address.value = c.address;
this.refs.description.value = c.description;
})
}
}
handleCreate(){
customersService.createCustomer(
{
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}
).then((result)=>{
alert("Customer created!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
handleUpdate(pk){
customersService.updateCustomer(
{
"pk": pk,
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}
).then((result)=>{
console.log(result);
alert("Customer updated!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
handleSubmit(event) {
const { match: { params } } = this.props;
if(params && params.pk){
this.handleUpdate(params.pk);
}
else
{
this.handleCreate();
}
event.preventDefault();
}
render() {
return (
);
}
}
export default CustomerCreateUpdate;
Создав компонентCustomerCreateUpdate, мы можем обновить основной компонентApp, чтобы добавить ссылки на различные компоненты, которые мы создали.
[[step-9 -—- update-the-main-app-component]] == Шаг 9 - Обновление основного компонента приложения
В этом разделе мы обновим компонентApp нашего приложения, чтобы создать ссылки на компоненты, которые мы создали на предыдущих шагах.
Из папкиfrontend выполните следующую команду, чтобы установитьReact Router, который позволяет добавлять маршрутизацию и навигацию между различными компонентами React:
cd ~/djangoreactproject/frontend
npm install --save react-router-dom
Затем откройте~/djangoreactproject/frontend/src/App.js:
nano ~/djangoreactproject/frontend/src/App.js
Удалите все, что там, и добавьте следующий код, чтобы импортировать необходимые классы для добавления маршрутизации. К ним относятсяBrowserRouter, который создает компонент Router, иRoute, который создает компонент маршрута:
~/djangoreactproject/frontend/src/App.js
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom'
import { Route, Link } from 'react-router-dom'
import CustomersList from './CustomersList'
import CustomerCreateUpdate from './CustomerCreateUpdate'
import './App.css';
BrowserRouter поддерживает синхронизацию пользовательского интерфейса с URL-адресом с помощьюHTML5 history API.
Затем создайте базовый макет, который предоставляет базовый компонент для обертывания компонентомBrowserRouter:
~/djangoreactproject/frontend/src/App.js
...
const BaseLayout = () => (
)
Мы используем компонентRoute для определения маршрутов нашего приложения; компонент, который маршрутизатор должен загрузить после обнаружения совпадения. Для каждого маршрута требуетсяpath, чтобы указать путь для сопоставления, иcomponent, чтобы указать компонент для загрузки. Свойствоexact указывает маршрутизатору соответствовать точному пути.
Наконец, создайте компонентApp, корневой или компонент верхнего уровня нашего приложения React:
~/djangoreactproject/frontend/src/App.js
...
class App extends Component {
render() {
return (
);
}
}
export default App;
Мы обернули компонентBaseLayout компонентомBrowserRouter, поскольку наше приложение предназначено для работы в браузере.
Готовый файл выглядит так:
~/djangoreactproject/frontend/src/App.js
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom'
import { Route, Link } from 'react-router-dom'
import CustomersList from './CustomersList'
import CustomerCreateUpdate from './CustomerCreateUpdate'
import './App.css';
const BaseLayout = () => (
)
class App extends Component {
render() {
return (
);
}
}
export default App;
После добавления маршрутизации в наше приложение мы готовы протестировать приложение. Перейдите кhttp://localhost:3000. Вы должны увидеть первую страницу приложения:

С этим приложением у вас теперь есть база для приложения CRM.
Заключение
В этом руководстве вы создали демонстрационное приложение с использованием Django и React. Вы использовали среду REST Django для создания API REST, Axios для использования API и Bootstrap 4 для стилизации вашего CSS. Вы можете найти исходный код этого проекта в этомGitHub repository.
В этой настройке учебника использовались отдельные интерфейсные и фоновые приложения. Чтобы узнать другой подход к интеграции React с Django, проверьте этоtutorial и этоtutorial.
Для получения дополнительной информации о создании приложения с помощью Django вы можете следить заDjango development series. Вы также можете посмотретьofficial Django docs.