【Django REST Framework】最短で REST API を実装する方法|シリアライザ・ビューセット・ルーターの基本

スポンサードリンク



Django REST Framework · API 開発入門

代の Web 開発では、フロントエンド(React / Vue / モバイルアプリ)とバックエンドを分離して、HTTP API でつなぐ設計が標準になっています。Django で REST API を作るなら、デファクトの拡張ライブラリ Django REST Framework(DRF) を使うのが定石です。本記事では、DRF のインストールから、シリアライザ・ビューセット・ルーターを使ったシンプルな REST API の実装手順を、最小限の構成で解説します。

本記事では、Django REST Framework(DRF)を使った簡単なAPIの作成手順をまとめました。

エンドポイントに対して銀行名を与えてGETメソッドを投げると支店名一覧を返すような簡単なREST APIを作成していきます。

user@sinyblog:~/article 01_section_1.md環境

今回は以下のバージョンで環境構築しました。

モジュール一覧
  • Django (3.0)
  • django-filter (2.2.0)
  • djangorestframework (3.10.3)

user@sinyblog:~/article 02_section_2.md事前準備

Django REST Frameworkを作成する前の事前準備を行います。

モジュールのインストール

仮想環境を作成後に以下のコマンドでモジュールをインストールします。

python


pip install django

pip install djangorestframework

pip install django-filter 

 

プロジェクト、アプリケーションの作成

Django REST Frameworkを作成するためにdjagnoプロジェクトとアプリケーションを作成します。

python


django-admin startproject bank_api

cd bank_api

python manage.py startapp appv1

 

settings.pyの設定

settings.pyにアプリケーションとrest_frameworkを追加します。

python


INSTALLED_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'rest_framework',          #add

    'appv1.apps.Appv1Config',  #add

]

 

user@sinyblog:~/article 03_django_rest_framewor.mdDjango REST Frameworkの作成

つづいて、Django REST Frameworkの作成です。

DjangoでDjango REST Frameworkを作成するには最低限以下の3つを定義する必要があります。

構成要素
  • Serializer
  • ViewSet
  • URL pattern

なお、ケースによりますが通常はモデルの定義も必要になってきます。

モデルの定義(models.py)

今回は以下のような銀行名と支店名コードのテーブルを例にDjango REST Frameworkを作成していきます。

python


from django.db import models





class Bank(models.Model):

    class Meta:

        verbose_name ="銀行名"

        verbose_name_plural = "銀行名"



    name = models.CharField("銀行名",max_length=255)

    bank_code = models.CharField("銀行コード",max_length=8)

    def __str__(self):

        return self.name





class Branch(models.Model):

    class Meta:

        verbose_name ="支店名"

        verbose_name_plural = "支店名"



    bank_name = models.ForeignKey(Bank, on_delete=models.CASCADE)	

    branch_name = models.CharField("支店名",max_length=255)

    branch_code = models.CharField("支店コード",max_length=6)

    def __str__(self):

        return self.branch_name

 

Serializerの定義(serializer.py)

 

Django REST Frameworkにおけるシリアライズ、デシリアライズは以下のような処理を表します。

シリアライズ     JSON文字列などをDjangoモデルオブジェクトに変換すること 
デシリアライズ モデルオブジェクトからJSON形式などに変換すること

 

また、Django REST Frameworkのシリアライザーには大きく以下の3種類があります。

serializerの処理 意味
ModelSerializer        単一のモデルオブジェクトを利用 
Serializer 単一のリソースを扱う、またはモデルに依存しないカスタマイズな処理を実装する
ListSerializer 複数リソースを扱う

 

今回は、Djangoモデル定義をそのまま活用するのでModelSerializerを使っていきます。

appv1/serializer.pyを作成し、以下のコードを記載します。

python


from rest_framework import serializers	

from .models import Bank, Branch





class BankSerializer(serializers.ModelSerializer):	

    class Meta:

        model = Bank

        fields = ('name', 'bank_code')	







class BranchSerializer(serializers.ModelSerializer):	

    class Meta:

        model = Branch

        fields = ('bank_name', 'branch_name', 'branch_code')	

 

ModelSerializerを使うと非常に簡単にREST APIのシリアライザを定義することができます。

Metaクラス内にmodel属性としてmodels.pyで定義したモデルクラス名を指定します。

そして、fieldsにAPIとして出力したいフィールド名を指定してあげます。

fields属性は以下のように指定可能です。

  • リストorタプル形式で指定
  • すべてのフィールドを指定する場合は「__all__
  • 除外設定した場合は、exclude = [branch_code']のようにする。

今回は銀行名を扱うBankSerializerシリアライザと銀行の支店名を扱うBranchSerializerの2つを定義しました。

 

ViewSetの定義(views.py)

続いてビューの定義です。

今回はrest_frameworkのModelViewSetを使います。

querysetにはすべてのレコードを格納するようにします。

serializer_classには利用したいシリアライザクラス(serializer.pyで定義したクラス)を指定します。

python


import django_filters			

from rest_framework import viewsets, filters

from .models import Bank, Branch

from .serializer import BankSerializer, BranchSerializer





class BankViewSet(viewsets.ModelViewSet):

    queryset = Bank.objects.all()

    serializer_class = BankSerializer





class BranchViewSet(viewsets.ModelViewSet):

    queryset = Branch.objects.all()

    serializer_class = BranchSerializer

 

URL pattern定義

次にアプリケーション配下にurls.pyを作成して以下を定義します。

python


from rest_framework import routers

from .views import BankViewSet, BranchViewSet



router = routers.DefaultRouter()

router.register(r'bank', BankViewSet)

router.register(r'branches', BranchViewSet)

 

ここでは、Django REST Frameworkのroutersというものを使ってModel毎に以下のようなURLパターンを定義しています。

  • GET /api/bank/ でBankモデルの一覧を取得
  • GET /api/branches/ でBranchモデルの一覧を取得

次にプロジェクト配下のurls.pyで先ほど定義したアプリケーションのurls.pyをインクルードしてあげます。

python


from django.contrib import admin

from django.urls import path, include

from appv1.urls import router as bank_api_router  #add





urlpatterns = [

    path('admin/', admin.site.urls),

    path('api/', include(bank_api_router.urls)),  #add

]

 

テストデータの登録

 

ここまできたら、一旦マイグレーション、管理者ユーザの作成後にrunserverします。

python


python manage.py makemigrations

python manage.py migrate

python manage.py createsuperuser

python manage.py runserver

 

次にadmin画面からテストデータを登録するためにadmin.pyに以下を定義します。

python


from django.contrib import admin

from .models import Bank, Branch





class BankAdmin(admin.ModelAdmin):

   list_display=('pk','name', 'bank_code')

 

class BranchAdmin(admin.ModelAdmin):

   list_display=('pk','bank_name', 'branch_name', 'branch_code')



admin.site.register(Bank, BankAdmin)

admin.site.register(Branch, BranchAdmin)

 

http://127.0.0.1:8000/adminにアクセスして銀行と支店情報をいくつか登録しておきます。

今回は4つの銀行と、三井住友の支店情報を4つだけ登録しておきます。

【銀行情報】

【支店情報】

 

 

API動作確認

 

開発サーバが起動したらhttp://127.0.0.1:8000/api/にアクセスして以下のようなAPIの画面が表示されることを確認します。

次に、銀行名の一覧表示用Rest API(http://127.0.0.1:8000/api/bank/)にアクセスして以下のように銀行名の一覧が表示されればOKです。

PK=1の銀行名のレコード(三井住友)にアクセスするにはhttp://127.0.0.1:8000/api/bank/1/のようにアクセスします。

ClientからJson形式でデータを取得する。

 

まず、クライアントPCのブラウザからhttp://127.0.0.1:8000/api/bank/?format=jsonのようにアクセスすると、以下のようにJSON形式で銀行名の一覧情報を取得できます。

text


[{"name":"三井住友","bank_code":"0009"},{"name":"三菱UFJ","bank_code":"0005"},{"name":"三菱UFJ信託","bank_code":"0288"},{"name":"三井住友信託","bank_code":"0294"}]

 

curlコマンドで取得した場合はcurl http://127.0.0.1:8000/api/bank/?format=json実行します。

※文字化けする場合はchcp 65001を実行

pythonコマンドから取得したい場合は以下のようなコードを実行します。

※以下は銀行名の一覧を抽出する例

python


>>> import requests

>>> import urllib.parse

>>> import json

>>> API = "http://127.0.0.1:8000/api/bank"

>>> values = {

...     "format": "json",

...     }

>>> params = urllib.parse.urlencode(values)

>>> url = API + "?" + params

>>> req = requests.get(url)

>>> data = json.loads(req.text)

>>> print(data)

[{'name': '三井住友', 'bank_code': '0009'}, {'name': '三菱UFJ', 'bank_code': '0005'}, {'name': '三菱UFJ信託', 'bank_code': '0288'}, {'name': '三井住友信託', 'bank_code': '0294'}]

>>> type(data)

<class 'list'>

>>> bank_list = [item['name'] for item in data]

>>> print(bank_list)

['三井住友', '三菱UFJ', '三菱UFJ信託', '三井住友信託']

>>>

 

カスタマイズ

 

次に支店情報一覧のAPI(http://127.0.0.1:8000/api/branches/)にアクセスしてみましょう。

以下の通り支店情報の一覧が表示されますが、bank_name(銀行名)の部分が外部テーブル参照になっている関係でPK番号で表示されていてちょっとわかりにくいです。

外部参照キーになっているbank_nameがPKキー表示になっているので、名称表示に変えてみます。

serializer.pyで定義したBranchSerializerクラスに以下のコードを追加します。

python


class BranchSerializer(serializers.ModelSerializer):

    bank_name = BankSerializer()  #追加	

    class Meta:

        model = Branch

        fields = ('bank_name', 'branch_name', 'branch_code')	

 

先ほどの画面を更新すると以下の通りbank_nameの部分がpk番号→銀行名、銀行コードに変わります。

ペジネーション

 

Django REST Frameworkで1回のリクエストで取得できる件数を制限し、必要に応じて次ページ分のデータを取得できるようにします。

ページネーションはsettings.pyに以下を追加するだけです。

python


REST_FRAMEWORK = {

    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',

    'PAGE_SIZE': 2

    }

 

その後画面を更新すると以下の赤枠のようにページネーション機能が追加されます。

フィルタ機能

 

次に、Django REST Frameworkにフィルタ機能を追加してみます。

フィルタ機能を利用するにはsettings.pyのINSTALLED_APPに「 'django_filters',」を追加します。

※django_filtersは最初にpipでインストール済み。

python


INSTALLED_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'rest_framework',

    'appv1.apps.Appv1Config',

    'django_filters', #add

]

 

さらにsettings.pyREST_FRAMEWORKDEFAULT_FILTER_BACKENDSを以下の通り追加します。

python


REST_FRAMEWORK = {

    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',

    'PAGE_SIZE': 2,

    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) 

    }

 

次にviews.pyのBranchViewSetにfilter_fields属性を追加します。

今回は銀行名でフィルタするものとします。

python


class BranchViewSet(viewsets.ModelViewSet):

    queryset = Branch.objects.all()

    serializer_class = BranchSerializer

    filter_fields = ('bank_name',)  #add

 

画面を更新すると、以下の通りFiltersボタンが追加され、銀行名でフィルタ検索できるようになります。

ちなみにこの時、URLは「http://127.0.0.1:8000/api/branches/?bank_name=1のようになっています。

通常リクエスト投げるときはbank_name=1という指定方法ではなく、銀行名を渡してリクエストの結果を受け取るという使い方が多いと思います。

先ほど設定したviews.pyのfilter_filedsの設定をbank_name → bank_name__nameに変更します。

これで、「http://127.0.0.1:8000/api/branches/?format=json&bank_name__name=<銀行名>'」という形式でリクエストを投げれるようになります。

python


class BranchViewSet(viewsets.ModelViewSet):

    queryset = Branch.objects.all()

    serializer_class = BranchSerializer

    filter_fields = ('bank_name__name',)  #修正

 

以下は、pythonコードでGETリクエスト('http://127.0.0.1:8000/api/branches?format=json&bank_name__name=三井住友)を投げる例です。

default


>>> bank_name="三井住友"

>>> API = "http://127.0.0.1:8000/api/branches"

>>> values = {

...     "format": "json",

...     "bank_name__name": bank_name,

...     }

>>> params = urllib.parse.urlencode(values)

>>> url = API + "?" + params

>>> url

'http://127.0.0.1:8000/api/branches?format=json&bank_name__name=%E4%B8%89%E4%BA%95%E4%BD%8F%E5%8F%8B'

>>> req = requests.get(url)

>>> data = json.loads(req.text)





>>> data

{'count': 4, 'next': 'http://127.0.0.1:8000/api/branches/?bank_name__name=%E4%B8%89%E4%BA%95%E4%BD%8F%E5%8F%8B&format=json&limit=2&offset=2', 'previous': None, 'results': [{'bank_name': {'name': '三井住友', 'bank_code': '0009'}, 'branch_name': '新宿支店', 'branch_code': '221'}, {'bank_name': {'name': '三井住友', 'bank_code': '0009'}, 'branch_name': '新橋支店', 'branch_code': '216'}]}

 

user@sinyblog:~/article 04_section_4.mdお勧めの書籍

Django REST Frameworkについては下記リンクの公式チュートリアルがあります(英語)

上記チュートリアルもわかりやすくて勉強になりますが、日本語書籍でDjango REST Frameworkに関するおすすめ書籍を1冊紹介しておきます。

akiyokoさんが執筆販売している書籍ですが、導入部では初心者の方にもわかりやすくDRFの概念やクラスの種類などが紹介されています。

かなり細部にわたってDjango REST Frameworkの仕組みを解説しているため、今後DRFを活用していきたい方は是非読んでおくことをお勧めします。

以上、「Django REST Frameworkで簡単なREST APIを実装する方法」でした。

おすすめの記事