Django REST frameworkのViewまとめ

# 1. Function based Views

`request`を受け取り`Response`を返す関数に`@api_view`デコレータを使用してビューを定義する．

```python
from rest_framework.decorators import api_view

@api_view(['GET', 'POST'])
def hello_world(request):
    if request.method == 'POST':
        return Response({"message": "Got some data!", "data": request.data})
    return Response({"message": "Hello, world!"})
```

`@permission_classes(...)`や`@renderer_classes(...)`などのデコレータを使用することで，設定を追加することができる．

# 2. Class based Views

`APIView`を継承したクラスによってビューを定義する．

```python
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from django.contrib.auth.models import User

class ListUsers(APIView):
    authentication_classes = [authentication.TokenAuthentication]
    permission_classes = [permissions.IsAdminUser]

    def get(self, request, format=None):
        usernames = [user.username for user in User.objects.all()]
        return Response(usernames)
```

`.get()`や`.post()`などをハンドラメソッドと呼ぶ．
送られてきたリクエストは設定されたパーミッション等のチェックを通った後，ハンドラメソッドに送られる．

# 3. Generic Views

いくつか用意されている汎用(ジェネリック)ビューを継承したクラスによって定義する．

```python
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser

# 作成と一覧取得ができるビュー
class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]
```

汎用ビューは`queryset`を設定し紐付けるため，基本的な動作をさせる場合は簡略化して書くことができる．
また，アクションメソッド(後述)等をオーバーライドして動作を拡張することもできる．

```python
class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]

    def list(self, request):# アクションメソッド
        queryset = self.get_queryset()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)
```

汎用ビューは共通の基底クラス`GenericAPIView`(後述)と基本的な動作を提供する`Mixin`(後述)を1つまたは複数継承している．各Mixinによって提供される動作は後述．

|汎用ビュー|継承しているMixin|
|:-|:-|
|CreateAPIView|CreateModelMixin|
|DestroyAPIView|DestroyModelMixin|
|ListAPIView|ListModelMixin|
|ListCreateAPIView|ListModelMixin, CreateModelMixin|
|RetrieveAPIView|RetrieveModelMixin|
|RetrieveDestroyAPIView|RetrieveModelMixin, DestroyModelMixin|
|RetrieveUpdateAPIView|RetrieveModelMixin, UpdateModelMixin|
|RetrieveUpdateDestroyAPIView|RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin|
|UpdateAPIView|UpdateModelMixin|

## GenericAPIView
`APIView`を拡張し，よく使われる動作を追加したクラス．すべての汎用ビューの基底．

`queryset`や`.get_queryset(self)`で使用するクエリセットを設定できる．
`.perform_create(self, serializer)`，`.perform_update(self, serializer)`，`.perform_destroy(self, instance)`でオブジェクトの保存・削除時の動作をオーバーライドできる．これらはMixinのアクションメソッドから呼び出される．

## Mixin

基本的なビューの動作を行うためのアクションメソッドを提供するクラス．

|Mixin|アクションメソッド|動作|
|:-|:-|:-|
|ListModelMixin|.list()|一覧取得|
|CreateModelMixin|.create()|作成|
|RetrieveModelMixin|.retrieve()|取得(単体)|
|UpdateModelMixin|.update()<br>.partial_update()|更新<br>部分更新|
|DestroyModelMixin|.destroy()|削除|

# 4. Viewsets

`viewsets.ModelViewSet`等を継承したクラスによって定義する．

```python
from django.contrib.auth.models import User
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response

class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    queryset = User.objects.all()
```

`ModelViewSet`はすべてのMixinが一緒になったようなクラス(実際すべてのMixinを継承している)で，これだけで取得・作成・一覧取得・更新・削除ができるようになる．
ビューセットはアクションメソッドを提供する(ハンドラメソッドではない)ので，機能を拡張したい場合はアクションメソッドをオーバーライドする．

|Viewsets|説明|
|:-|:-|
|ViewSet|APIViewを継承．アクションメソッドを提供せず，使う場合は明示的にオーバーライドする必要がある．|
|GenericViewSet|GenericAPIViewを継承．queryset等の設定ができる．明示的にアクションメソッドをオーバーライドするか，Mixinと一緒に継承する．|
|ModelViewSet|GenericViewSetと各Mixinを継承．各種アクションメソッドを提供する．|
|ReadOnlyModelViewSet|GenericViewSetとRetrieveModelMixin，ListModelMixinを継承．取得と一覧取得のみを提供する．|

# 各クラスの継承関係
![Class Inheritance](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549339/44cc0e0d-4b89-679d-be00-6d26858e731e.png)

# 参考
本記事の内容及びサンプルコードは以下を参考・引用した．

https://www.django-rest-framework.org/

https://www.cdrf.co/

https://note.crohaco.net/2018/django-rest-framework-view/