Учебник для начинающих
В этом руководстве мы узнаем, как создать приложение CRUD Todo с фреймворком Django REST для внутреннего интерфейса, React и Redux для внешнего интерфейса.
В конце этого урока у нас будет приложение, которое выглядит так:
Оглавление
- Настройка Django
- Настройка React
- Получение данных из API и отображение списка
- Создание формы и добавление нового Todo
- Создание заголовка
- Удаление Todos
- Редактирование Todos
Настройка Django
Создание виртуальной среды с Pipenv
Сначала мы создадим папку для проекта и перейдем в нее:
$ mkdir django-react-todo $ cd django-react-todo
Давайте создадим виртуальную среду, выполнив эту команду:
$ pipenv --python 3
Если у вас еще не установлен Pipenv, установите его, выполнив следующую команду:
$ pip install pipenv
Установим нужные нам пакеты:
$ pipenv install django djangorestframework
Создание нового проекта и некоторых приложений
В этом руководстве мы создадим проект под названием «todocrud». Мы можем опустить дополнительную папку, которая создается автоматически, если добавить точку в конец команды и запустить:
$ django-admin startproject todocrud .
Далее мы создадим два приложения. Один для бэкэнда, другой для фронтенда:
$ python manage.py startapp todos $ python manage.py startapp frontend
Мы откроем файл settings.py
в каталоге проекта и настроим использование созданных нами приложений и инфраструктуры Django REST:
Мы можем указать выходной формат даты и времени, включив DATETIME_FORMAT
в словарь конфигурации с именем REST_FRAMEWORK
.
Применим миграции и запустим сервер разработки:
$ python manage.py migrate $ python manage.py runserver
Посетите http://127.0.0.1:8000/ в своем браузере. Если вы видите страницу взлетающей ракеты, значит, она сработала!
Написание модулей backend
Сначала мы создадим простую модель. Откройте файл models.py
и напишите следующий код:
Затем мы создадим простой API на основе модели с использованием инфраструктуры REST. Давайте создадим новую папку с именем api
и создадим в ней новые файлы __init__.py
, serializers.py
, views.py
и urls.py
:
todos/ api/ __init__.py serializers.py urls.py views.py
Поскольку api
- это модуль, нам нужно включить __init__.py
файл.
Давайте определим представление API в файле serializers.py
:
Класс ModelSerializer
создаст поля, соответствующие полям модели.
Затем мы определим поведение представления в файле api/views.py
:
Наконец, мы напишем конфигурацию URL, используя Routers
:
Мы используем три аргумента метода register()
, но третий аргумент не требуется.
Написание модулей внешнего интерфейса
В интерфейсе все, что нам нужно сделать, это написать простые представления и шаблоны URL.
Откройте файл frontend/views.py
и создайте два представления:
Мы создадим файл frontend/index.html
позже. Не беспокойся об этом сейчас.
Добавьте новый urls.py
файл в тот же каталог и создайте URL conf:
Как вы можете видеть выше, представление index
предназначено для страницы индекса, а TodoDetailView
вызывается, когда мы запрашиваем конкретный объект.
Подключите URL-адреса
Мы включим URL-адреса внешнего и внутреннего интерфейса в URLconf проекта:
Хотя путь к сайту Django admin
оставлен, мы не собираемся использовать его в этом руководстве.
В заключительной части этой главы мы создадим новый файл миграции и внесем изменения в наши базы данных, выполнив следующие команды:
$ python manage.py makemigrations $ python manage.py migrate
Настройка React
Создание каталогов
Прежде всего, создадим все нужные нам каталоги:
$ mkdir -p ./frontend/src/{components,actions,reducers} $ mkdir -p ./frontend/{static,templates}/frontend
Приведенная выше команда должна создать каталоги следующим образом:
frontend/ src/ actions/ components/ reducers/ static/ frontend/ templates/ frontend/
Установка пакетов
Нам нужно создать файл package.json
, выполнив следующую команду перед установкой пакетов:
$ npm init -y
Для использования npm
необходимо установить Node.js.
Затем давайте установим все используемые нами пакеты с помощью команды npm
:
$ npm i -D webpack webpack-cli $ npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties $ npm i react react-dom react-router-dom $ npm i redux react-redux redux-thunk redux-devtools-extension $ npm i redux-form $ npm i axios $ npm i lodash
Создание файлов конфигурации
Добавьте файл с именем .babelrc
в корневой каталог и настройте Babel:
Мы можем использовать Async / Await с Babel, написав, как указано выше.
Во-вторых, добавьте файл с именем webpack.config.js
в тот же каталог и напишите конфигурацию для webpack
:
Кроме того, нам нужно переписать свойство "scripts”
файла package.json
:
Были определены два новых скрипта. Мы можем запускать сценарии с npm run dev
для разработки или npm run build
для производства. При запуске этих сценариев webpack
объединяет модули и выводит main.js
файл.
Создание основных файлов
Давайте создадим три основных файла и отобразим первое слово.
Мы создадим файл с именем index.js
, который будет вызываться первым при запуске приложения React:
Затем мы создадим файл с именем App.js
, который является родительским компонентом:
Наконец, мы создадим файл шаблона с именем index.html
, который указан в файле views.py
:
В этом руководстве мы будем использовать Semantic UI как основу CSS.
Поместите оболочку для рендеринга компонента App и связанного скрипта в тег <body>
.
Проверка дисплея
Посмотрим, правильно ли он отображается.
Откройте другой терминал и запустите скрипт:
$ npm run dev
Файл main.js
должен быть создан в каталоге static/frontend
.
Затем запустите сервер разработки и зайдите на http://127.0.0.1:8000/:
$ python manage.py runserver
Если отображается слово «ToDoCRUD», пока все идет хорошо :)
Получение данных из API и отображение списка
Пора использовать Redux. Мы создадим Действия, Редукторы и Магазин.
Действия
Заранее определим все свойства типа. Добавьте новый файл с именем types.js
в каталог src/actions
:
Чтобы создать действия, нам нужно определить Создатели действий. Добавьте новый файл с именем todos.js
в каталог src/actions
:
Редукторы
Редукторы определяют, как состояние приложения изменяется в ответ на действия, отправленные в магазин.
В этом роль редукторов. Добавьте новый файл с именем todos.js
в каталог src/reducers
и напишите дочерний редуктор:
Lodash - это служебная библиотека JavaScript. Это не является обязательным требованием, но может сократить время разработки и уменьшить размер кодовой базы.
Давайте создадим родительский редуктор, чтобы собрать каждый дочерний редуктор с помощью combineReducers()
. Добавьте новый файл с именем index.js
в каталог src/reducers
:
Чтобы использовать redux-form
, нам нужно включить его редуктор в функцию combineReducers
.
Магазин
Магазин - это объект для хранения состояния нашего приложения. Кроме того, мы будем использовать рекомендованное промежуточное ПО Redux Thunk для написания асинхронной логики, которая взаимодействует с хранилищем. Давайте создадим новый файл с именем store.js
в каталоге src
:
Использование Redux DevTools необязательно, но очень полезно, поскольку позволяет визуализировать изменения состояния Redux. Я не буду здесь рассказывать, как его использовать, но настоятельно рекомендуется.
Компоненты
Сначала создайте новую папку с именем todos
в каталоге components
. А затем добавьте новый файл с именем TodoList.js
в созданную нами папку:
Мы используем список семантического пользовательского интерфейса для украшения списка.
Функция connect()
подключает этот компонент к магазину. Он принимает mapStateToProps
в качестве первого аргумента, а Создатели действий - в качестве второго аргумента. Мы сможем использовать состояние магазина как свойства, указав mapStateToProps
.
Мы создадим новый файл с именем Dashboard.js
в том же каталоге. Это просто контейнер для TodoList
и форма, которую мы создадим в следующей главе:
Откройте файл App.js
и обновите его следующим образом:
Provider
делает хранилище доступным для вложенного в него компонента.
Проверка дисплея
Сначала зайдите на http://127.0.0.1:8000/api/todos/ и создайте несколько объектов. Затем зайдите на http://127.0.0.1:8000/.
Вы должны увидеть простой список созданных вами объектов. Это сработало?
Создание формы и добавление нового Todo
Действия
Откройте файл actions/todos.js
и добавьте новый создатель действий:
Отправка reset('formName')
очищает нашу форму после успешной отправки. Мы укажем имя формы позже в компоненте Форма.
Редукторы
Откройте файл reducers/todos.js
и добавьте новое действие в редуктор:
Компоненты
Давайте создадим компонент формы. Мы создадим форму отдельно как компонент многократного использования, чтобы ее также можно было использовать для редактирования. Создайте новый файл с именем TodoForm.js
в каталоге components/todos
:
Учебник будет длинным, поэтому я опущу, как использовать Redux Form. Чтобы понять, как работает Redux Form, неплохо попробовать настроить вашу форму, ссылаясь на документацию.
'todoForm'
- это имя этой формы. Это то, что мы использовали в создателе действий addTodo
.
Когда мы щелкаем текстовое поле и затем удаляем фокус, отображается ошибка проверки, поэтому укажите touchOnBlur: false
, чтобы отключить ее.
Затем давайте создадим компонент для добавления новых задач. Создайте новый файл с именем TodoCreate.js
в каталоге components/todos
:
Все, что нам нужно сделать, это отрендерить TodoForm
. Установив destroyOnUnmount
на false
, мы можем отключить автоматическое уничтожение формы Redux Form в хранилище Redux при размонтировании компонента. Он предназначен для отображения состояния формы в форме редактирования.
Если нам не нужно указывать mapStateToProps
функцию, установите null
на connect()
.
Давайте посмотрим и протестируем форму. Откройте файл Dashboard.js
и обновите его следующим образом:
Создание заголовка
Сделаем перерыв и создадим заголовок. Создайте новую папку с именем layout
, а затем добавьте в нее новое имя файла Header.js
:
Откройте файл App.js
и вложите компонент Header
:
В этом уроке заголовок - это просто украшение.
Удаление Todos
Сначала мы создадим объект history
с помощью пакета history. Мы можем использовать его для изменения текущего местоположения. Создайте новый файл с именем history.js
в каталоге frontend/src
и напишите приведенный ниже код:
Действия
Откройте файл actions/todos.js
и добавьте два новых средства создания действий:
Мы создали getTodo
, чтобы получить конкретный объект, и deleteTodo
, чтобы удалить объект.
Позже мы создадим модальное окно для подтверждения удаления. Метод history.push('/')
автоматически переводит нас из модального окна на страницу индекса после удаления объекта.
Редукторы
Откройте файл reducers/todos.js
и добавьте действия в редуктор:
Действие GET_TODO
такое же, как действие ADD_TODO
, поэтому нам нужно только установить case
. Для действия DELETE_TODO
снова используйте Lodash как ярлык.
Компоненты
Давайте создадим модальное окно, о котором я только что говорил. У нас получится вот так:
Создайте новый файл с именем Modal.js
в каталоге components/layout
и напишите следующее:
Чтобы отобразить компонент Modal
вне иерархии DOM родительского компонента, создайте портал, используя createPortal()
. Первый аргумент - это рендерируемый дочерний элемент, а второй аргумент - это элемент DOM для рендеринга.
Затем откройте файл index.html
и добавьте контейнер для модального окна внутри тега <body>
:
Затем мы создадим новый компонент TodoDelete.js
в каталоге components/todos
:
Код длинноват, но это не так уж и сложно. Определите вспомогательные функции, отображающие содержимое и кнопки действий в модальном окне. Затем передайте их как свойства в модальный компонент. onDismiss
настроен на возврат к странице индекса при щелчке по тусклой части модального окна.
Мы можем получить данные из его собственных свойств, указав ownProps
в качестве второго аргумента для mapStateToProps
.
Давайте откроем TodoList.js
файл и поставим кнопку удаления:
Наконец, нам нужно настроить маршрутизацию с помощью React Router. Откройте файл App.js
и настройте следующим образом:
Причина использования Router
вместо BrowserRouter объясняется в документе REACT TRAINING следующим образом:
Наиболее распространенный вариант использования низкоуровневого ‹Router› - это синхронизация пользовательской истории с библиотекой управления состоянием, такой как Redux или Mobx. Обратите внимание, что это не требуется для использования библиотек управления состоянием вместе с React Router, это только для глубокой интеграции.
Параметр exact
, указанный в Route
, возвращает маршрут, только если path
точно соответствует текущему URL-адресу.
На этом завершаем эту главу. Попробуйте удалить некоторые объекты и посмотрите, работает ли это.
Редактирование Todos
Это последняя глава. Мы почти закончили, так что давайте продолжим!
Действия
Откройте файл actions/todos.js
и добавьте новый создатель действий:
Редукторы
Откройте файл reducers/todos.js
и добавьте действие в редуктор:
Компоненты
Создайте новый компонент TodoEdit.js
в каталоге components/todos
:
Укажите объект в initialValues
. Мы можем получить только значение task
с помощью _.pick
функции Lodash. Кроме того, установите enableReinitialize
в true
, чтобы мы также могли получить значение при перезагрузке страницы. Передайте эти необязательные свойства в TodoForm
.
Откройте файл TodoList.js
и обновите <a className='header'>{todo.task}</a>
следующим образом:
Давайте добавим новый компонент в App.js
файл:
Наконец, давайте изменим текст кнопки в форме редактирования с «Добавить» на «Обновить». Откройте файл TodoForm.js
и обновите его следующим образом:
Теперь щелкните любую задачу на странице индекса и попробуйте отредактировать:
Вы должны были изменить значение в форме.
На этом урок заканчивается. Исходный код этого приложения доступен на GitHub. Спасибо за чтение!