아래 사례는 Udemy의 "The complete Guide to Django Restframework and Vue JS" 강의 중 Section4 의 : Django REST Framework - Level Two 내용으로서 Ebook API 작성사례이며, DRF 9편까지 이어집니다.
GenericaAPIVeiw Tutorial 보러 가기
GenericAPIView
에 List, Create 등 다양한 믹스인 클래스를 결합해 APIView를 구현할 수 있음GenericAPIView
는 CRUD(생성/읽기/수정/삭제)에서 공통적으로 사용되는 속성을 제공하고, Mixin은 CRUD 중 특정 기능을 수행하는 메소드를 제공함from rest_framework import generics
from rest_framework import mixins
from ebooks.models import Ebook
from ebooks.api.serializers import EbookSerializer
class EbookListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Ebook.objects.all()
serializer_class = EbookSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
다음 속성들을 통해 View를 컨트롤함
다음 속성을 통해 리스트뷰에서 페이지네이션을 컨트롤하게 된다.
DEFAULT_PAGINATION_CLASS
(rest_framework.pagination.PageNumberPagination 모듈안에) 세팅으로 결정됨.왜 믹스인 클래스를 사용할까? 만약 Django Rest Framework Mixin을 사용하지 않다면, 모든 기능을 모든 VIew에 직접, 반복적으로 구현해야할 것이다. 하지만 API를 작업할 때 목록을 보여주거나, 생성, 삭제, 수정 등은 항상 사용되는 반복적인 일이다. 이러한 반복적인 기능을 하나의 Mixin 클래스로 제공한다면 반복적인 일을 줄여주고 가독성, 생산성을 높여줄 수 있다.
단, Mixin 클래스에 존재하는 메소드나 속성을 상속받는 클래스에서 사용할 경우 믹스인 클래스의 메소드가 오버라이딩되어 의도하지 않게 작동할 수 있으니 주의해야한다.
.list(request, *args, **kwargs)
메소드로 호출하여 사용200 OK response
리턴.create(request, *args, **kwargs)
메소드로 호출하여 사용201 Created
리턴400 Bad Request
리턴.retrieve(request, *args, **kwargs)
메소드로 호출하여 사용200 OK response
리턴404 Not Found
리턴.update(request, *args, **kwargs)
메소드로 호출하여 사용.partial_update(request, *args, **kwargs)
메소드를 호출하여야 하며, 이 때 요청은 HTTP PATCH requests
여야 함200 OK response
리턴404 Not Found
리턴.destroy(request, *args, **kwargs)
메소드로 호출하여 사용204 No Content
리턴404 Not Found
리턴View -> APIView -> GenericAPIView로 View클래스의 기능이 더 많아지는데, 각 View별로 어떤 차이점이 있는가?
APIView
는 위에서 봤듯이 각 request method 마다 직접 serializer
처리를 해주었습니다.
하지만 이러한 부분들은 많이 사용되므로 여러 serializer
에 대해서 중복이 발생합니다.
따라서 rest_framework.mixins
에서는 이러한 기능들이 미리 구현이 되어 있습니다.
이름이 굉장히 직관적이므로 각각에 대한 자세한 설명은 생략하겠습니다.
queryset
과 serializer_class
를 지정해주기만 하면 나머지는 상속받은 Mixin
과 연결해주기만 하면 됩니다.
# views.py
from rest_framework.response import Response
from rest_framework import generics
from rest_framework import mixins
from .models import Post
from .serializers import PostSerializer
class PostListMixins(mixins.ListModelMixin, mixins.CreateModelMixin,generics.GenericAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
def get(self, request, *args, **kwargs):
return self.list(request)
def post(self, request, *args, **kwargs):
return self.create(request)
class PostDetailMixins(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
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.delete(request, *args, **kwargs)
이에 대한 urls 입니다.
# urls.py
from django.urls import path, include
from . import views
urlpatterns = [
# Mixin
path('mixin/post/', views.PostListMixins.as_view()),
path('mixin/post/<int:pk>/', views.PostDetailMixins.as_view()),
]
결과 화면은 위와 동일하므로 생략하도록 하겠습니다.
Mixin 을 상속함으로서 반복되는 내용을 많이 줄일 수 있었습니다. 하지만 여러 개를 상속해야 하다보니 가독성이 떨어집니다. 다행히도 rest_framework 에서는 저들을 상속한 새로운 클래스를 정의해놨습니다.
총 9개의 클래스로 다음과 같습니다.
하나만 예시로 살펴보면 위에서 해주었던 Mixin 과 GenericAPIView 상속, 각 request method 에 대한 연결을 해주고 있습니다.
# rest_framework/generics.py
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
이를 통해 코드를 많이 줄일 수 있습니다.
# views.py
from rest_framework import generics
from .models import Post
from .serializers import PostSerializer
class PostListGenericAPIView(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetailGenericAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
urls 와 결과 화면은 중복되므로 생략하도록 하겠습니다.
감사합니다.