Автор выбрал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
npm
5.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
. Он содержит переменные состояния нашего компонента, используя пустойcustomers
array. Этот массив будет содержать клиентов и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.