DjangoはPythonによるWebアプリケーションのためのフレームワークです。Djangoは元々要求(Request)を元に画面を作ってそれをResponseとして返す機能を持っていますが、本書で扱っている事例では、画面はブラウザ側で生成するSPAシステムなので、バックエンドは画面からの要求に応じてデータを返すRest APIを提供する役割が求められます。DjangoにこのようなAPI機能を提供するのが、Django Rest framework(以下DRFと呼びます)というフレームワークです。
7.0 とりあえず動かしてみる
まずは、非常に簡単なアプリケーションプログラムを作って動かしてみます。なぜこれで動くものができるのかは7.1章以降で説明しますので、
7.0.1 準備 (アプリケーションフォルダーを作って登録)
まず、最初に「drf_sample」という名前のアプリケーションフォルダを作ります。Djangoに登録しておきます。
% python manage.py startapp drf_sample
settings.pyを編集して、作ったアプリケーションをDjangoに登録しておきます。
#backend/settings.py
INSTALLED_APPS = [
"polls.apps.PollsConfig",
"drf_sample.apps.DrfSampleConfig", # <- 追加
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
7.0.2 プログラムを作る
drf_sample/models.pyを編集
# drf_sample/models.py
from django.db import models
class Todo(models.Model):
title = models.CharField("タイトル", max_length=200)
is_done = models.BooleanField("完了フラグ", default=False)
drf_sample/serilizers.pyを追加
# drf_sample/serilizers.py
from rest_framework import serializers
from .models import Todo
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
# API で扱いたいフィールドを列挙
fields = ["id", "title", "is_done", "created_at"]
drf_sample/views.pyを編集
# drf_sample/views.py
from rest_framework import generics
from .models import Todo
from .serializers import TodoSerializer
class TodoListCreateView(generics.ListCreateAPIView):
#GET: Todo 一覧 / POST: Todo 新規作成
queryset = Todo.objects.all()
serializer_class = TodoSerializer
class TodoRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
#GET: 1件取得 / PUT/PATCH: 更新 / DELETE: 削除
queryset = Todo.objects.all()
serializer_class = TodoSerializer
7.0.3 URLディスパッチャーに登録
drf_sample/urls.pyを作成
# drf_sample/urls.py
from django.urls import path
from .views import TodoListCreateView, TodoRetrieveUpdateDestroyView
urlpatterns = [
path("todos/", TodoListCreateView.as_view(), name="todo-list"),
path("todos/<int:pk>/", TodoRetrieveUpdateDestroyView.as_view(), name="todo-detail"),
]
(backend)/urls.pyを編集
# (backend)/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include(“drf_sample.urls")), # ← /api/todos/... の入り口になる
]
7.0.4 データベースに反映
データベースにモデルの定義を反映します。makemigrationsとmigrateを実行します。
% python manage.py makemigrations drf_sample
Migrations for 'drf_sample':
drf_sample/migrations/0001_initial.py
+ Create model Todo
% python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, drf_sample, polls, sessions
Running migrations:
Applying drf_sample.0001_initial... OK
7.0.5 テスト
データベースにテスト用のデータを登録します。プロジェクトフォルダに、次のようなJSON形式で記述したファイルを作り、これをデータベースに読み込みます。
# fixture.json
[
{"model": "drf_sample.Todo","pk": 1, "fields":{"title" : "記事を書く", "is_done" : false}},
{"model": "drf_sample.todo","pk": 2, "fields": {"title" : "ソフトウェア設計をする", "is_done" : true}},
{"model": "drf_sample.todo","pk": 3, "fields": {"title" : "プログラムを作る", "is_done" : false}},
{"model": "drf_sample.todo","pk": 4, "fields": {"title" : "テストをする", "is_done" : false}}
]
djangoのユーティリティツールmanage.pyを使って、ファイルに記述した内容をデータベースにロードします。
% python manage.py loaddata fixture.json
開発用のサーバーを起動しておきます。
% python manage.py runserver
この状態で、作ったプログラムをテストするのですが、この際「curl」というコマンドを使います。curlはコマンドラインからHTTPリクエストを送信するためのツールです。URLを指定してデータを取得したり、データを送信したりすることができます。(Macではデフォルトで搭載されています。)
(1)GETリクエストを送信し、データの一覧を取得する
% curl localhost:8000/api/todos/
# 実行結果
[{"id":1,"title":"記事を書く","is_done":false},{"id":2,"title":"ソフトウェア設計をする","is_done":true},{"id":3,"title":"プログラムを作る","is_done":false},{"id":4,"title":"テストをする","is_done":false}]
(2)POSTリクエストを送信し、データを追加する
% curl -X POST \
-H "Content-Type: application/json" \
-d '{"title": "Test the code" , "is_done" : false}' \
http://localhost:8000/api/todos/
# 実行結果
{"id":5,"title":"Test the code","is_done":false}
(3)PUTリクエストを送信し、データを更新する
% curl -X PUT \
-H "Content-Type: application/json" \
-d '{"title":"Test the code" , "is_done" :false}'\
localhost:8000/api/todos/2/
# 実行結果
{"id":2,"title":"Test the code","is_done":false}
(4)DELETEリクエストを送信し、データを削除する
% curl -X DELETE localhost:8000/api/todos/2/
注意:
上記のように単純にcurlでPOST, PUT, DELETEをテストすると "
403 Forbidden" のエラーが返ってくるかもしれません。(多分そうなります)Djangoのデフォルト設定では、リクエストのヘッダに有効な CSRFトークン が含まれているかを厳格にチェックしており、これが原因でForbiddenとなります。CSRFトークンはWebサイトへの不正な書き込みや操作(CSRF攻撃)を防ぐための仕組みなのですが、curlで機能を確認する際には、以下のように「一時的に」クラスの前に@method_decoratorを記載して、CSRF攻撃防止機能をオフにしてください。
# drf_sample/views.py from rest_framework import generics from .models import Todo from .serializers import TodoSerializer@method_decorator(csrf_exempt, name='dispatch' # <- 追加class TodoListCreateView(generics.ListCreateAPIView):#GET: Todo 一覧 / POST: Todo 新規作成 queryset = Todo.objects.all() serializer_class = TodoSerializer@method_decorator(csrf_exempt, name='dispatch') # <- 追加class TodoRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView): #GET: 1件取得 / PUT/PATCH: 更新 / DELETE: 削除 queryset = Todo.objects.all() serializer_class = TodoSerializer
もちろんこれは、開発中のみの措置であり、本番システムでは使ってはいけません。
7.1 Django +DRFの仕組み ~どんな風に動くのか~
以下、Django+DRFでどのようにRest APIを提供するWebアプリケーションが動作するかを詳しく見ていきます。
DjangoはWebサーバを介してブラウザーからのRequestを受け取り、それに応じた処理を行なって、データをResponseとして返します。

(1) ミドルウェア
渡されたRequestはまずミドルウェアによって処理されます。ミドルウェアは受け取ったRequestやResponseに対し、情報を追加したり加工したりするなどの処理を行います。複数のミドルウェアを登録することができ、例えば元々組み込まれているミドルウェアには以下のようなものがあります。
- SecurityMiddleware : HTTP による要求であった場合 HTTPS へのリダイレクトを要求するレスポンスを返したり、応答にセキュリティ関連の情報 を追加します。
- SessionMiddleware : ユーザーを管理するためなどの「セッション」を使う際に、リクエストやレスポンスにセッションデータを追加します。
- CommonMiddleware : URL リダイレクト (「www」プレフィックスの追加/削除)などURLに対する処理を行います。
- CsrfViewMiddleware : クロスサイト リクエスト フォージェリ (CSRF) 攻撃に対する保護のためCSRF トークンの追加や検証を行います。
- AuthenticationMiddleware : 現在ログインしているユーザーの情報をリクエストに追加します。
これらは、ユーザ管理やセキュリティ対策に関連していますので、詳しくは後の「マルチテナント化」「セキュリティ対策」でも説明します。
(2)URLディスパッチャ
渡されたリクエストのURLを解析して、どの処理にリクエストを渡すのかを決めるのがURLディスパッチャです。urls.pyというファイルに解析方法を記載しておくことで、指定されたURLに対応するdjangoにおけるviewが呼び出されます。
# urls.py
urlpatterns = [
path(‘Sample/‘, SampleView.as_view(), name="bulk_create"),
path(‘DetailedSample/<pk>/, DetailedSampleView.as_view(), name="bulk_create"),
]
urlpatternsの最初の行では、Sample/'というURLにHTTPリクエストが送られると、SampleView という名前のViewが呼び出され、リクエストが渡されます。
次の行の場合は、URLの中の<pk>のところににキー値がセットされたHTTPリクエストが送られると、SamleViewという名前のViewが呼び出されます。この時、プライマリーキー「pk」の値も、併せて、Viewに伝えられます。例えば URLが ”HTTP://woo.foo.com/DetailedSample/1/“ だった場合、DetailedSampleViewのクラスメソッドas_view()が呼び出され、as_viewの引数であるkwargsに{‘pk’ : ‘1’}がセットされます。
(3)View
DjangoにおけるViewは、何らかの処理を行なってその結果を返すアプリケーションプログラムです。ViewはRequestを受け取り、処理(データの取得、データの変更・削除、取得したデータの加工など)を行なった結果をResponseとして返します。
このアプリケーション用のViewのプログラミングが開発の肝で、Djangoでのソフトウェア開発のほとんどを占めます。DjangoやDRFは、非常に少ないコード量でこの Viewプログラミングを行う仕組みを提供してくれます。