Django REST Frameworkを使ってみる

はじめまして。Marketing Solution Divisionに所属している新人データサイエンティストの山嵜です。ARISE analyticsでは、データ分析を通して様々な企業のマーケティングのサポートを実施しております。その一環として、自社開発プロダクトのAnalytics Platform(APF)を導入して頂くことにより、機械学習を用いたマーケティングの内製化支援もしています。

前回の記事ではフレームワークを使った開発作業の効率化という点に着目し、Pylanceの良さをご紹介させて頂きました。今回の記事では、実際のフレームワークそのものに着目し、APFの開発にも用いられているDjango REST Frameworkについてご紹介します。

Django REST Framework(DRF)とは?

Django REST Frameworkとは、一言で表すと「RESTful API開発に特化したDjangoのフレームワーク」です。Djangoは元々PythonでWebアプリを作成するためのフレームワークですが、TwitterやGithubなどのWebサービスにも用いられているRESTful API(※)を開発する上では、HTTP requestごとに機能を実装するためのアーキテクチャがないため、コードが煩雑かつ複雑になってしまいます。また、画面などの構成は含まずにデータだけをやりとりしたい場合には、専用の処理を実装する必要があります。そこで、そのようなニーズに答えるためにDjango REST Framework(DRF)が登場しました。

(※) RESTful APIについて
「アドレス可能性」・「ステートレス性」・「接続性」・「統一インターフェース」の4つのRESTの原則に基づいて設計されたAPI。スケーラビリティの高さ、統一インターフェースなどのメリットがあり、昨今のWebサービスでは広く用いられています。より詳細な説明は他ページ参照(https://qiita.com/TakahiRoyte/items/949f4e88caecb02119aa)。

DRFの立ち位置

PythonでRESTful APIを作成するフレームワークとしてはDRF以外にもFlaskやFastAPIなどが挙げられます。ここで、以下3つの基準にしたがってこれらのフレームワークを比較してみます。

  1. 表現力(豊富なモジュールを持ち、少ないコード量で複雑なロジックを実装することができるか?
  2. リファレンスの充実度(参考文献の量・質の高さは十分か?)
  3. 学習コスト(新規参画者でも数日〜数週間でキャッチアップ可能か?)

    DRFの大きな特徴

    簡単な設定をするだけでRESTful APIバックエンド構築の手間が省けることです。たとえば次のような機能がデフォルトで含まれています。

    • ユーザー認証
    • ユーザー・グループ毎のアクセス権の制御
    • クエリ⽂字列によるページリソースの検索
    • ページ毎のJSONレスポンス(ページネーション)
    • アクセス回数などの制限(スロットリング)

    以上から、表現力の高さ・バックエンド構築の手軽さなどを考慮し、APFの開発ではDRFを用いてAPIを開発しております。

    実際にやってみた(APIを作ってみる)

    ここまでDRFについて説明してきましたが、「そうは言うけど実際DRFってどうなの?」と思っている方もいらっしゃるでしょう。そこで以降では、DRFを使って実際にRESTful APIを実装してみます。今回はDRFの表現力の高さに着目し、3つの書き方を紹介します。

    まず、HTTP requestの「POST(登録)」とPOSTのタイミングで別の処理(ここではhogeメソッド)が実行されるスクリプトを以下2つの書き方で実装していきます。

    a.rest_framework.views.APIViewを使用

    b.汎用APIViewを使用

    さらに、POSTと「GET(取得(一覧))」を同時に実装する例として、

    c.rest_framework.mixins.CreateModelMixinを使用する書き方を紹介してます。

    また、ページの都合上実装はViewのみとさせていただき、Model・Serializerについてはすでに実装済みとします(コード中ではそれぞれ、本のモデル<Book>、本モデルのシリアライザ<BookSerializer>と表現)。DRFについてのより詳しい説明は公式および、Djangoの公式を参照してください。(DRF公式Django公式

    a. rest_framework.views.APIViewを使用

    from django.shortcuts import get_object_or_404
    from rest_framework import status, views
    from rest_framework.response import Response
    
    from .models import Book
    from .serializers import BookSerializer
    
    
    class BookListCreateAPIView(views.APIView):
        """本モデルの登録APIクラス"""
    
        def post(self, request, *args, **kwargs):
            """本モデルの登録APIに対応するハンドラメソッド"""
    
            # シリアライザオブジュエクトを作成
            serializer = BookSerializer(data=request.data)
            # バリデーション
            serializer.is_valid(raise_exception=True)
            # モデルオブジェクトを登録
            serializer.save()
            # hogeメソッドの実行
            hoge()
    
            # レスポンスオブジェクトを返す
            return Response(serializer.data, status.HTTP_201_CREATED)

    対応するHTTP requestの名前でメソッドを記述してあげるだけで実装することができます。

    b. 汎用APIViewを使用(rest_framework.generics.ListAPIViewを実装するViewに継承)

    from rest_framework import generics
    from rest_framework import status
    from rest_framework.response import Response
    
    from .serializers import BookSerializer
    
    
    class BookListCreateAPIView(generics.CreateAPIView):
        """本モデルの登録APIクラス"""
    
        serializer_class = BookSerializer
    
        def create(self, request, *args, **kwargs):
            # 継承元クラスのcreateメソッドがvalidationなどの処理を一括で実行する
            response = super().create(request)
            # hogeメソッドの実行
            hoge()
    
            return Response(status=status.HTTP_201_CREATED)

    aの場合よりもさらに記述量が少なく、HTTP requestに対応するメソッド(ここではcreate)をoverrideすることで実装することができます。

    c. rest_framework.mixinsを使用

    from rest_framework import generics
    from rest_framework import mixins, status, viewsets
    from rest_framework.response import Response
    
    from .models import Book
    from .serializers import BookSerializer
    
    class BookListCreateAPIView(mixins.CreateModelMixin,
                                mixins.ListModelMixin,
                                viewsets.GenericViewSet):
        """本モデルの登録APIクラス"""
    
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        def create(self, request, *args, **kwargs):
            # 継承元クラスのcreateメソッドがvalidationなどの処理を一括で実行する
            response = super().create(request)
            # hogeメソッドの実行
            hoge()
    
            return Response(status=status.HTTP_201_CREATED)

    bの場合とほぼ同じ書き方ですが、それはbのコード中のgenerics.CreateAPIViewはもともとmixins.CreateModelMixin継承したものであるためです。mixins.ListModelMixinを継承し、querysetを追加するだけでGETも実装されます。

    おわりに

    今回はRESTful API実装フレームワークDRFについての紹介と実装例をご紹介させていただきました。
    ARISE analyticsではAPF以外にもさまざまなプロダクトを開発しております。機会がありましたら今回ご紹介できなかった他のフレームワークについてもご紹介できたらと思います。