Django/restframework

DRF tutorial - 3 Class-based Views

두잇 두두 2024. 1. 2. 21:40
728x90

목표

이번 tutorial 3에서는 기존 작성했던 함수 형식의 class 기반의 view로 작성해서 더 가독성 있고 코드 길이를 줄이는 것을 배우는 것이 목표입니다.

 

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class SnippetList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

앞서 작성한 함수 기반 view는 이렇게 class 기반 view로 만들 수 있습니다

 

class SnippetDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """
    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            raise Http404

    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)

detail view 또한 이렇게 class 기반으로 코드를 만들 수 있습니다.

그리고 클래스 기반 뷰를 사용하게 되서 urls.py 또한 약간의 리팩토링이 필요합니다

urlpatterns = [
    path('snippets/', views.SnippetList.as_view()),
    path('snippets/<int:pk>/', views.SnippetDetail.as_view()),
#     path('snippets/', views.snippet_list),
#     path('snippets/<int:pk>/', views.snippet_detail),
]

 

위 두개의 Class들은 앞선 함수 기반 view와 비슷하게 생겨서 차이점이 무엇인지 궁금할 것입니다!

Using mixins

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics

class SnippetList(mixins.ListModelMixin,
                    mixins.CreateModelMixin,
                    generics.GenericAPIView
                  ):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

GenericAPIView, ListModelMixin, CreateModelMixin을 이용해서 view를 구축하고 있습니다.

기본 class도 코어 기능을 제공하고 mixnin class들은 .list(), .create()를 제공합니다 우리는 이것들을 명시적으로(explicitly)

get과 post에 바인딩 해줍니다. 굉장히 간단합니다!

 

class SnippetDetail(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

다시 한번 더 GenericAPIView class가 코어 기능을 제공하고 mixins를 통해 .retrieve(), .update() 그리고 .destroy() 기능들을 제공합니다

이렇게 mixin class들을 사용해서 코드들을 약간 덜 사용하도록 작성했지만 여기서 한 단계 더 나아갈 수 있습니다!

Using generic class-based views

REST framework는 이미 generic view와 mixied-in이 되어있는 기능을 제공합니다. 우리는 이것을 이용해서 우리의 view를 다듬을 수 있습니다

 

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

와 이렇게나 코드가 짧아 질 수 있나요

 

이렇게 저희는 3장 Class-based Views를 배워봤습니다