React HooksとDjango REST Frameworkを使ってTo Do Listを作ってみた(後編)〜バックエンド編
前回に引き続き、React(フロントエンド)+Django(バックエンド)によるTo Do Listアプリを作っていきます。
今回はバックエンド編です。
環境構築
Djangoを利用しますので、任意の名前の仮想環境を構築しておきます。
当該仮想環境を立ち上げて、以下をインストールします。
pip install django pip install djangorestframework pip install django-cors-headers
djangorestframework
はDjango REST Framework
を利用するためのもので、django-cors-headers
は、ReactアプリのアドレスとDjangoのアドレスが異なっているため、通常ではブラウザは通信できません。ReactアプリとDjangoが適切にAPI通信を行うために必要なモジュールとなります。
私の環境における各バージョンは以下の通りです。
Django 3.0 djangorestframework 3.11.1 django-cors-headers 3.4.0
Djangoの設定
Django プロジェクト及びアプリの作成
まずは、Djangoプロジェクトを作成します。任意のプロジェクト名をつけますが、ここではtodoproj
としています。
そしてtodoproj
フォルダに移動し、そこでdjangoアプリを作成します。ここではアプリ名をtodoapp
としています。
django-admin startproject todoproj cd todoproj python manage.py startapp todoapp
settings.pyの設定
todoprojフォルダ傘下のsettings.py
を以下の通り修正します。
INSTALLED_APPS = [ ... 'rest_framework', # <- 追加 'corsheaders', # <- 追加 'todoapp.apps.TodoappConfig' # <- todoappを追加 ] ## django-cors-headersを利用する場合 MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', ..... ] # Djangoが通信する相手であるReactアプリのポートを指定 CORS_ORIGIN_WHITELIST = [ 'http://localhost:3000' ]
Djangoアプリの書き方
それでは、Django REST Frameworkを利用したアプリを具体的に記述していきます。
モデル(models.py)
Django REST Frameworkを利用する場合であっても、このモデルの作成は通常のDjangoと同様となります。したがって、models.pyにdjango.db.models.Modelを継承したクラスとして定義します。
Reactアプリで使っているfieldをここで定義します。id
はReact側でuuidを自動的に付与しますので、ここではCharField
(文字列)とします。また、primary_key=True
としないとmakemigration
時に警告が出てきます。その他title
を文字列としてisCompleted
をBool値として設定します。
from django.db import models class Task(models.Model): id = models.CharField(max_length=128, primary_key=True) title = models.CharField(max_length=256) isCompleted = models.BooleanField(default=False) def __str__(self): return self.title
シリアライザ(serializers.py)
シリアライザは、データを保持しておくための入れ物で、JSON文字列とモデルオブジェクトの相互変換をしてくれるものです(「現場で使えるDjango REST Frameworkの教科書」)。
今回は、Taskモデルでの定義に基づき、JSONの入出力が行われるため、ModelSerializer
を継承したシリアライザを利用することができます。これにより、モデルのフィールド定義が内部的に再利用されるため、このsirializers.py
での記述が非常に簡単になります。
具体的には以下の通り。
from rest_framework import serializers from .models import Task class TaskSerializer(serializers.ModelSerializer): class Meta: model = Task fields = ['id', 'title', 'isCompleted']
ビュー(views.py)
このビューの役割は、JSONデータが入ったリクエストオブジェクトを受け取り、APIの種類に応じた処理を実行し、JSON形式のレスポンスオブジェクトを返すことです。
今回のモデルは、Taskのみの単一モデルなので、ModelViewSet
を利用すれば、CRUDを処理するAPIを簡単に実装することができます。
具体的には、views.py
を以下のとおり最低限記述するだけで利用可能ととなります。
from rest_framework import viewsets from .serializers import TaskSerializer from .models import Task class TaskViewSet(viewsets.ModelViewSet): queryset = Task.objects.all() serializer_class = TaskSerializer
URLconf(Urls.py)
URLconfとはURLのパターンの集まりで、適切なビューを見つけるために、DjangoがリクエストされたURLと照合するものです。
API用のURLパターンを新たに設定する場合、通常のDjangoと同様にurlpatternsリストにpath関数等を利用して、URLパターンとビューのセットを記載します。
# todoproj/settings.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('todoapp.urls'))
なお、ModelViewSetを継承した場合には、Django REST Framework独自のRouter
クラスを使って設定します。
# todoapp/settings.py from django.urls import path, include from rest_framework import routers from .views import TaskViewSet router = routers.DefaultRouter() router.register('tasks', TaskViewSet) urlpatterns = [ path('', include(router.urls)) ]
これでdjangoを起動して、ブラウザのアドレスバーにhttp://127.0.0.1:8000/api/tasks
を入力すると、ブラウザ上にtasks(task一覧)が表示されるようになります。
なお、DjangoのAdmin管理画面でTaskの登録状況が一応見られるように、以下のとおり登録しておきます。
from django.contrib import admin from .models import Task admin.register(Task)
以上で準備は完了です。
それでは、仮想環境になっていることを確認して、python manage.py rumserver
で Djangoを起動させます。
そしてアドレスバーにhttp://127.0.0.1:8000/api/tasks
を入力すると以下の画面が立ち上がりました。まだ、データは登録していないので、ブランクリストが表示されていますね。
データをいくつか登録しておきましょう。
下側のhtml form
の記載のあるボックスに「id」「title」「isCompleted」が入力できるようになっているので、適当に入力してPOST
を押すと登録できます。
id
は文字列で他のtaskと重ならないように以下のとおり入力してみました。
id: a001
title: Reactを学習する
isCompleted: チェック
id: a002
title: お米を買う
isCompleted: チェックしない
id: a003
title: お酒を買う
isCompleted: チェックをしない
上段のボックスのGET
をクリックします。すると以下のとおり、Task Listが表示されました。
なお、入力済みの個別taskの修正や削除を行いたい場合は、アドレスバーに http://127.0.0.1:8000/api/tasks/a001
と最後にid
を入力します。すると以下のとおり、個別明細とPUT
やDELETE
表示が出ますので、適宜修正や削除が可能です。
ここでは、「学習する」を「勉強する」に修正しておきました。
Reactアプリと繋げる
さて、いよいよReactアプリとDjangoを接続します。まずはReactアプリを修正して、json-serverではなく、Djangoに接続できるように設定します。
Reactアプリの修正
baseUrlを以下のとおり修正します。
細かいところですが、add
の場合とupdate
の場合には、${baseUrl}/
や${baseUrl}/${id}/
と最後に/
をつけないとエラーとなってしまいます。
import axios from 'axios'; // const baseUrl = "http://localhost:3001/tasks"; const baseUrl = "http://localhost:8000/api/tasks"; async function getAll () { const response = await axios.get(baseUrl); return response.data; } async function add (newTask) { const response = await axios.post(`${baseUrl}/`, newTask) return response.data; } async function update(id, updatedTask) { const response = await axios.put(`${baseUrl}/${id}/`, updatedTask) return response.data; } async function _delete(id) { await axios.delete(`${baseUrl}/${id}`); return id; } export default { getAll, add, update, delete: _delete }
これで準備が整いました。
React アプリのあるフォルダ(ここではmytodo
)に移動し、npm start
でアプリを立ち上げます。
無事にDjangoと接続できました。
djangoプロジェクトのtodoprojの下にfrontend
というフォルダを作成し、その下にmytodo
を移動しておくと、djangoとの関係性が明確で良いかと思います。
今回は単純なアプリでしたが、それでもHooksの概念がなかなか理解できず(副作用って一体何?だったり、Hooksの種類がいろいろあったりで)、手間取ったところもありましたが、何とかイメージしたことは実装できました。
今後は、ユーザー登録機能だったり、順番を入れ替える、期日管理を行うなど実装にチャレンジしたいなとは思っています。ただ、やりたいことが結構増えてしまっていますので、いつになるか分かりませんが...