Django REST framework(1)
モデルの定義の次は、RESTful APIの実装に取り掛かりましょう。Djangoコミュニティには、Web API構築の際に便利なパッケージが数多くありますが、今回はデファクトスタンダードとなっているDjango REST frameworkを使用していきます。
Django REST frameworkのほかにどのようなパッケージがあるのかは、Django PackageというサイトのAPI Creationのページから調べられます。このDjango Packageは開発頻度や特徴などが一覧・比較でき、Django関連のパッケージを調べる際には重宝します。
Django REST frameworkをインストールして、settingsを更新しておきましょう。
(env) $ pip install djangorestframework
Collecting djangorestframework
Downloading djangorestframework-3.7.7-py2.py3-none-any.whl (1.1MB)
100% |████████████████████████████████| 1.1MB 10.3MB/s
Installing collected packages: djangorestframework
Successfully installed djangorestframework-3.7.7
(env) $ vi requirements/base.txt
(env) $ cat requirements/base.txt
Django==2.0.2
django-model-utils==3.1.1
djangorestframework==3.7.7
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # rest_frameworkを追加
'kanban.board.apps.BoardConfig',
]
設定はこれだけで完了です。Django REST frameworkの機能を使って、Ticketモデルを操作するRESTful APIの実装を進めていきます。
シリアライザーの作成
シリアライズとは、オブジェクトをバイト列など出力可能なデータに書き出すことです。日本語では直列化とも呼ばれます。デシリアライズとは、逆にソフトウェアで扱うために元の形式に復元する処理のことを指します。Djano REST frameworkのModelSerializerを利用すると、Djangのモデルオブジェクトのシリアライズ・デシリアライズが簡単に実装できます。
APIのレスポンスとして、先ほど作成したTicketオブジェクトを、次のようなJSONとして出力することを目指していきます。
{
"id": 1,
"name": "ticket 1",
"description": "This is the first ticket.",
"status": 1,
"status_display": "ToDo",
"assignee": "massa142",
"start": null,
"end": null
}
kanban/board/serializer.pyファイルを作成して、TicketSerializerを以下のように実装します。
from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import Ticket
User = get_user_model()
class TicketSerializer(serializers.ModelSerializer):
assignee = serializers.SlugRelatedField(
slug_field=User.USERNAME_FIELD, queryset=User.objects.all(), allow_null=True)
status_display = serializers.SerializerMethodField()
class Meta:
model = Ticket
exclude = ('created', 'modified')
def get_status_display(self, obj):
return obj.get_status_display()
Metaオプションのそれぞれの役割は以下の通りです。
| オプション名 | 役割 |
|---|---|
| model | serializerが扱うモデルを指定 |
| exclude |
serializerが扱わないフィールドを指定(扱うフィールドを指定する場合はfieldsオプションを使用) |
statusはデータとしては単なる数値でしかないので、そのまま出力しても何をする値かわからず扱いづらいです。そのため人間にもわかりやすい文字列データを、読み込み専用のstatus_displayフィールドとして定義します。
このstatus_displayフィールドは、serializers.SerializerMethodFieldとして実装しています。SerializerMethodFieldはデフォルトでread_onlyになっており、get_<field_name>メソッドを通じて値を返します。そのメソッドを実装しているのが、以下のコードです。
def get_status_display(self, obj):
return obj.get_status_display()
このobj.get_status_display()とは、statusフィールドのchoicesオプションで指定した表示用の文字列を取得できるメソッドです。言葉で説明するよりもコードを見たほうが理解しやすいと思うので、以下のコードを確認してください。
(env) $ python manage.py shell_plus >>> ticket = Ticket.objects.get(id=1) >>> ticket.status 1 >>> ticket.get_status_display() 'ToDo'
これはDjangoの備え付けの機能で、choicesオプションを持つすべてのフィールドでget_<field_name>_display()メソッドが使えます。
またassigneeには、SlugRelatedFieldを適用しています。SlugRelatedFieldは、ForeignKeyなどリレーション関連のフィールドに対して使用します。slug_fieldオプションでは、出力する際に使用するリレーション先のフィールドを指定しています。またquerysetで指定した値は、入力値のバリデーションに使われます。allow_nullは、このフィールドにNULLとなる値を許可するかどうかを決めています。
以上でSerializerの実装がひとまず完成しました。次はこのSerializerを使ったview.pyの実装に移りましょう。
ビューの作成
Django REST frameworkが用意しているModelViewSetを利用すると、HTTPメソッドに対応してDjangoモデルのCRUD操作を行うview関数の実装が簡単にできます。
kanban/borad/view.pyファイルを以下のように実装します。
from rest_framework import viewsets
from .models import Ticket
from .serializers import TicketSerializer
class TicketViewSet(viewsets.ModelViewSet):
queryset = Ticket.objects.all()
serializer_class = TicketSerializer
一覧表示に実行されるquerysetと、シリアライズ・デシリアライズで使用するserializer_classを指定するだけでOKです。このようにModelViewSetはモデルに密接に紐づいていて、開発者にとっては抽象度が高いものとなっています。
ここで実装したビューをURLのルーティングに紐づけて実際にアクセスできるようにするために、ルーターの設定を次に行いましょう。
ルーターの設定
Django REST frameworkは、上記で実装したようなViewSetを扱うために便利なURLルーティング機能を提供しています。config/urls.pyを次のように編集しましょう。
from django.urls import include, path
from django.contrib import admin
from rest_framework.routers import DefaultRouter
from kanban.board.views import TicketViewSet
router = DefaultRouter()
router.register('tickets', TicketViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
]
router.registerの第一引数にはURLプリフィックスを、第二引数にはViewSetを指定して、ルーティングに登録していきます。そしてurlpatternsに、url('^api/', include(router.urls))を追加しています。これで/api/配下にrouterに登録したルーティングルールを反映できます。
