안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

장고 (Django)

[Django] REST framework - ③ Class-based Views

피그브라더 2020. 6. 27. 13:11

본 포스팅은 아래 링크의 내용을 나름대로 정리한 글이다.

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

 

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

 

1. REST API 뷰 정의하기 (APIView 클래스 이용)

이번에는 DRF가 제공하는 APIView 클래스를 이용하여 우리가 작성한 뷰들을 클래스 기반의 뷰들로 리팩토링 해보자. 각 메소드의 동작을 함수 단위로 보기 좋게 분리하였음을 볼 수 있다.

 

▼ 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):
    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)


class SnippetDetail(APIView):
    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)

 

2. REST API 뷰 정의하기 (mixin 클래스 이용)

우리가 지금까지 뷰에 정의한 List, Create, Retrieve, Update, Delete의 기능들은 어떠한 백 엔드 애플리케이션의 API 뷰에서도 자주 사용이 되는 것들이다. 따라서 그러한 공통의 기능들은 DRF가 mixin 클래스들을 통해 이미 정의를 해놓았다. 다음은 DRF가 제공하는 mixin 클래스들을 활용하여 우리가 정의한 뷰들을 리팩토링 한 결과이다.

 

▼ snippets/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)


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 클래스를 상속함으로써 REST API 뷰로서의 핵심 기능을 상속받고, 각 동작(List, Create, Retrieve, Update, Delete)에 해당하는 mixin 클래스를 추가로 상속함으로써 해당 동작을 정의할 수 있게 되었다. 우리가 작성해줘야 하는 부분은 오로지 각 메소드에 해당하는 함수에 이미 구현되어 있는 해당 동작들을 연결해주는 것뿐이다.

 

3. REST API 뷰 정의하기 (mixed-in generic 클래스 이용)

놀랍게도 여기서도 한 단계 더 나아가 뷰를 간소화할 수 있는 방법이 있다. 우리가 정의한 뷰를 보면 List와 Create가 하나의 뷰로, 그리고 나머지가 하나의 뷰로 정의되어 있음을 알 수 있다. 이는 실제로 자주 사용되는 패턴이며, 따라서 DRF가 이러한 뷰의 작성을 위한 클래스들도 별도로 마련해놓았다. 이를 활용하여 우리가 정의한 뷰들을 또다시 리팩토링 해보자. 말도 안 되게 간결해진 것을 볼 수 있다.

 

▼ 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

 

4. 마무리의 말

지금까지 DRF의 기능을 활용하여 간편하게 REST API 뷰를 정의하는 법을 알아보았다. 다음 포스팅에서는 로그인을 통한 유저의 권한 인증과 각 API의 접근에 대한 권한을 통제하는 방법에 대해 다뤄보도록 하자.