Django REST framework (DRF) でModelViewSetを部分的に使いたい


ModelViewSet

Django Rest Framework(DRF)ではModelViewSetというクラスが用意されています.これを使うと基本的なAPIViewをまとめて一発で実装できます.
また,ModelViewSetを使えば,urls.pyに記述する各メソッドのエンドポイントもrest_framework.routersクラスを使って簡単に実装できるようになります.安定したURI設計にも役立ちますね.
可読性も良くなります.

ModelViewSetには以下のメソッドが実装されています.

.list()            # 全件取得
.retrieve()        # 1件取得
.create()          # 作成
.update()          # 更新
.partial_update()  # 部分更新
.destroy()         # 削除

部分的に利用したい

この中で一部のメソッドだけ実装したい場合どうしようとなりました.
APIViewで必要なメソッドだけを選んで逐一実装して行く方法があると思います.しかし今回はViewSetの良さを活かしたいです.

つまり例えば以下のクラス

views.py
class HogeViewSet(viewsets.ModelViewSet):

Createできないようにしたい場合,CreateAPIView以外のものを書く

views.py
class HogeListView(generics.ListAPIView):
class HogeRetrieveView(generics.RetrieveAPIView):
class HogeUpdateView(generics.UpdateAPIView):
class HogeDeleteView(generics.DestroyAPIView):

クラス数が増える! urls.pyの行数も増える!可読性も下がりそう!
そのままの感じでどうにかできないだろうか.

ということが今回の記事の内容です.

ModelViewSetの中身

Djangoのカスタマイズをしたい場合Githubのレポジトリを見ればいいと考えています.リファレンスももちろん見ます.
DRFのレポジトリを確認します.

/rest_framework/viewsets.py
class ModelViewSet(
                mixins.CreateModelMixin,
                mixins.RetrieveModelMixin, 
                mixins.UpdateModelMixin, 
                mixins.DestroyModelMixin, 
                mixins.ListModelMixin, 
                GenericViewSet): 
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass

ModelViewSetはGenericViewSetとmixinを多重継承して実装されているだけなのです.

不要なmixinを削れば良い

答えはシンプルで不必要なmixinを消せばよいということです.
例えば自作のユーザーモデルについて,ユーザー作成(create)は他の方法(django-allauthとか)で実装したいけどそれ以外の処理は一つにまとめておきたい.そういうモデルビューを作成したい時に今回のやりかたを使いました.

views.py
from .models import CustomUser
from .serializer import CustomUserSerializer
from rest_framework import viewsets
class CustomUserViewSet(viewsets.ModelViewSet):

    queryset = CustomUser.objects.all()
    serializer_class = CustomUserSerializer
    .
    .
    .

views.py
from .models import CustomUser
from .serializer import CustomUserSerializer
from rest_framework import viewsets, mixins

# mixins.CreateModelMixinを継承していないのでcreate()はできない.
class CustomUserViewSet(
                   mixins.RetrieveModelMixin, 
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   viewsets.GenericViewSet):

    queryset = CustomUser.objects.all()
    serializer_class = CustomUserSerializer
    .
    .
    .

できた.

まとめ

  • ViewSetはまとめてくれて便利
  • ModelViewSetはModelmixinとGenericViewSetを継承している.
  • メソッドを削減したいならmixinを削ればいい.

見返すとたいした内容ではないのですが
DRFに関する日本語の情報はあまりないので少しでも誰かの役に立てばなあと思います.
何かあればご指摘お願いします.
以上です.ありがとうございました!