DEV Community

kaede
kaede

Posted on

Django REST FRAMEWORK Tutorial 10 -- def snippet_list を Class SnippetList に書き直す

何が変わるのか

https://www.django-rest-framework.org/tutorial/3-class-based-views/

@api_view(['GET', 'POST'])
def snippet_list(request, format=None):
    if request.method == 'GET':
    elif request.method == 'POST':
Enter fullscreen mode Exit fullscreen mode

@api_view の後に def で snippet_list で関数を作って
request.method によって if で分岐して処理していた。

class SnippetList(APIView):
    def get(self, request, format=None):
    def post(self, request, format=None):
Enter fullscreen mode Exit fullscreen mode

これを SnippetList という class を作って
get, post のメソッドごとに 関数を作る構成にする


こうすることで、全体を指すものはクラス、各自メソッドを指すものは関数
と分けることができるのでコードが見やすくなると推測する。

また、get_object を関数にして各メソッドから呼び出すようにすることで
コードの可読性が良くなると推測する。



SnippetList のコードを書いていく

api_view の書き換えと Class SnippetList の全体像

from rest_framework.decorators import api_view
Enter fullscreen mode Exit fullscreen mode

今まで関数の前に使っていた api_view から

from rest_framework.views import APIView
Enter fullscreen mode Exit fullscreen mode

クラスの引数として用いる APIView に変更

class SnippetList(APIView):
    def get(self, request, format=None):
    def post(self, request, format=None):
Enter fullscreen mode Exit fullscreen mode

こうして class と def で書き直す。
中身はのロジックは以前 if で分岐していた時と全く同じ。



snippet_detail を書き直す

こちらは新たに作成される get_object が依然と大きく異なる。

全体構成

class SnippetDetail(APIView):
    def get_object(self, pk):
    def get(self, request, pk, format=None):
    def put(self, request, pk, format=None):
    def delete(self, request, pk, format=None):
Enter fullscreen mode Exit fullscreen mode

このように、SnippetDetail クラスの中に
関数を作っていく。


get_object の用途

以前は def snippet_detail 直下で

    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)
Enter fullscreen mode Exit fullscreen mode

最初に try で snippet 変数に取ってきておいて

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)
Enter fullscreen mode Exit fullscreen mode

各メソッドでは、その snippet を使うようにしていた。

これを今回は

    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            raise Http404
Enter fullscreen mode Exit fullscreen mode

オブジェクトを取ってくる一つの関数 get_object に切り出して

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)
Enter fullscreen mode Exit fullscreen mode

各メソッド関数で self から self.get_object として 使用する。
JavaScript の this のようなものだと解釈する。


get_object を実際に書く

from django.http import Http404
Enter fullscreen mode Exit fullscreen mode

Http404 を使うので import して

    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            raise Http404
Enter fullscreen mode Exit fullscreen mode

get_object では pk に応じてオブジェクトを取得し
なければ Http404 を返す。
別の関数に切り出し Http404 を使う以外は前回と変更点はない。


get, put, delete

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
Enter fullscreen mode Exit fullscreen mode

全てのメソッド関数で self から get_object を使って
現在の primary key のオブジェクトを取ってくるようにする。


urls に クラス名を適用して .as_view() もつける。

snippets/urls.py を見ると

urlpatterns = [
    path('snippets/', views.snippet_list),
    path('snippets/<int:pk>/', views.snippet_detail),
]
Enter fullscreen mode Exit fullscreen mode

以前は views. snippet_list になっていたが

class と APIView を使うとこれでは読み込めない。

    path('snippets/', views.SnippetList.as_view()),
    path('snippets/<int:pk>/', views.SnippetDetail.as_view()),
Enter fullscreen mode Exit fullscreen mode

views. の後に SnippetList, SnippetDetail と
CamelCase に直したクラス名を記述して
.as_view() をつける。

これでクラスベースで読み込まれるようになった。

Top comments (0)