SW개발/Django

[Django]Django REST Framework 튜토리얼 3 (Class-based Views)

 

이번 포스팅에서는 DRF의 Class-based Views 공식 문서를 공부하면서 번역해보려고 한다.

해석에 틀린 내용이 있을 수 있으니 이해가 안가는 부분은 아래의 공식문서를 참조하기 바란다.

 

DRF Class-based Views tutorial 공식 Documentation
 

3 - Class based views - Django REST framework

We can also write our API views using class-based views, rather than function based views. As we'll see this is a powerful pattern that allows us to reuse common functionality, and helps us keep our code DRY. We'll start by rewriting the root view as a cla

www.django-rest-framework.org

함수 기반 뷰가 아닌 클래스 기반 뷰를 이용하여 API View를 작성할 수도 있다. 보시다시피 이것은 일반적인 기능을 재사용하고
코드를 DRY 하게 유지하는데 도움이 되는 강력한 패턴이다.

 

Rewriting our API using class-based views

루트 view를 클래스 기반 뷰로 재 작성할 것이다. 아래는 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):
    """
    코드 snippet의 목록을 보여주거나, 새로 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 methods를 더 잘 구분하였다.

또한 views.py에서 instance view(SnippetDetail)도 업데이트 해야 한다.

class SnippetDetail(APIView):
    """
    snippet을 검색, 업데이트, 삭제
    """
    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 를 약간 리팩토링해야 한다.

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)

좋아 끝났다. 서버를 실행시키면 이전과 같이 잘 작동하는 것을 확인할 수 있다.

 

Using mixins

클래스 기반 뷰 사용의 가장 큰 장점중 하나는 재사용이 쉽게 가능하다는 것이다.

지금까지 사용한 Create/Retrieve/Update/Delete 명령은 일반적으로 모델을 사용할 때의 뷰와 비슷하다.

이러한 일반적인 동작은 REST framework에서 Mixin 클래스로 구현되어있다. 

Mixin 클래스를 사용하여 구성하는 방법을 알아볼 것이다. views.py 모듈에서 살펴보자.

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를 사용하여 뷰를 작성하고, ListModeMixin과 CreateModeMixin을 추가하였다.

GenericApiView는 핵심 기능을 제공하고 Mixin 클래스는 .list() .create() 기능을 제공한다.

그런 다음 이 기능들을 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는 핵심 기능을 제공하고 나머지 Mixin들이 .retrive(), .update(), .destroy() 와 같은 기능을 제공한다.

 

Using generic class-based views

Mixin 클래스를 사용하여 이전의 코드에 비해 양이 줄어들었지만, 다음 과정을 진행하면 더 줄일 수 있다. REST framework는 이미 mixinGeneric View를 결합한 것을 제공한다. 이를 사용하면 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

코드가 굉장히 간결해졌다. 큰 노력을 들이지 않고 많은 기능을 구현하였는데 코드는 Django 답게 깔끔해졌다.

tutorial part 4 에서는 API에서 인증과 권한을 어떻게 다루는 지 살펴볼 것이다.

 

728x90