Skip to content

5. Class-based Views


1. Rewriting our API using class-based views

  • 함수 기반의 뷰를 클래스 기반의 뷰로 다시 작성해 보자.
  • snippets/views.py 파일을 열어 다음과 같이 수정한다.


snippets/views.py
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)


  • 함수 기반의 뷰와 매우 유사해 보이지만 서로 다른 HTTP 메서드를 더 잘 구분할 수 있다.


  • 나머지 함수 기반의 뷰를 클래스 기반의 뷰로 다시 작성해 보자.


snippets/views.py
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)


  • 이제 클래스 기반의 뷰로 수정했기 때문에 snippets/urls.py 파일 또한 리팩토링해야 한다.


snippets/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

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

urlpatterns = format_suffix_patterns(urlpatterns)


2. Using mixins

  • 클래스 기반의 뷰 사용의 큰 장점 중 하나는 재사용 가능한 동작을 쉽게 구성할 수 있다는 것이다.
  • 지금까지 사용했던 생성/검색/업데이트/삭제 작업은 앞으로 생성하는 모든 모델 지원 API 뷰와 매우 유사할 것이다.
  • 공통으로 동작하는 것들은 REST framework의 mixins 클래스에서 구현된다.
  • mixins 클래스를 사용하여 뷰를 구성하는 방법을 살펴보기 위해 snippets/views.py 파일을 열어 다음과 같이 작성한다.


snippets/views.py
from Django.tutorial.snippets.models import Snippet
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 클래스를 사용하여 뷰를 작성하고, ListModelMixinCreateModelMixin을 추가한다.
  • 기본 클래스는 핵심 기능을 제공하고 mixins 클래스는 .list().create() 작업을 제공한다.
  • 그런 다음 getpost 메서드를 적절한 작업에 명시적으로 바인딩한다.


  • 나머지 클래스 기반의 뷰도 마저 수정해 보자.


snippets/views.py
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 클래스를 사용하여 핵심 기능을 제공하고, mixins 클래스를 추가하여 .retrieve(), .update(), .destroy() 작업을 제공한다.


3. Using generic class-based views

  • mixins 클래스를 사용하여 이전보다 더 적은 코드를 사용하도록 뷰를 다시 작성했지만, 더 줄일 수 있다.
  • REST framework는 snippets/views.py 파일을 더 다듬는 데 사용할 수 있는 혼합된(mixed-in) 일반(generic) 뷰 세트를 제공한다.


snippets/views.py
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

References