📌 이 포스팅에서는 Django Rest Framework의 Mixins, Generics, ViewSets을 사용하여 더 간결하게 CBV를 구현하는 방법에 대해 정리하였습니다.
🔥 Mixins를 활용하여 CRUD 구현하기
🔥 Generics를 활용하여 CRUD 구현하기
🔥 ViewSets를 활용하여 CRUD 구현하기
✔️ DRF에서 지원하는 mixins는 실제 python에서 제공하는 mixins 문법이 없기 때문에 클래스의 상속 문법을 활용한다.
✔️ 아래 5가지 mixins를 모듈로써 제공한다.
- CreateModlMixin : post 요청 받았을 때, 생성할 때 create하는 로직
- ListModelMixin : get 요청 받앗을 때, 목록 조회
- RetrieveModelMixin : get 요청 받았을 때, 상세 보기 조회
- UpdateModelMixin : put 또는 patch 요청 받았을 때, 수정
- DestroyModelMixin : delete 요청 받았을 때, 삭제
✔️ "models.py", "serializers.py", "urls.py"는 기존("FBV로 CRUD 구현하기" 편)과 같기 때문에 생략한다.
✔️ Mixins에서 제공하는 View를 사용하기 위해 rest_framework에서 generics, mixins를 import 해준다.
✔️ Mixins를 상속받아 사용하면, queryset과 serializer_class를 지정하고, 필요 매서드를 작성하면 된다.
✔️ 이에 중복이 사라지고 간결해지는 장점이 있다. 목록은 list, 생성은 post, 상세 보기는 get, 수정은 update, 삭제는 delete 매서드를 이용하여 반환한다.
from rest_framework import generics, mixins # 👈 generics, mixins 가져오기 from fbvApp.models import Student from fbvApp.serializers import StudentSerializer # StudentList class StudentList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer def get(self, request): return self.list(request) def post(self, request): return self.create(request) # StudentDetail class StudentDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer def get(self, request, pk): return self.retrieve(request, pk) def put(self, request, pk): return self.update(request, pk) def delete(self, request, pk): return self.destroy(request, pk)
✔️ generic의 ListCreateAPIView, RetrieveUpdateDestoryAPIView를 상속하면 더 간결하게 구현이 가능하다.
✔️ genrics APIView의 종류는 아래와 같다. 다양한 조합으로 사용가능 하다.
- generics.CreateAPIView : post 요청일 때, create의 매핑되어 object 생성
- generics.ListAPIView : get 요청일 때, list와 매핑되어 object list 제공
- generics.RetrieveAPIView : get 요청일 때, retrieve와 매핑되어 object 상세 정보 제공
- generics.DestroyAPIView : delete 요청일 때, destory와 매핑되어 object 삭제
- generics.UpdateAPIView : put 요청일 때는 update, patch 요청일 때는 partial_update와 매핑
- generics.ListCreateAPIView : CreateAPIView와 ListAPIView를 통합
- generics.RetrieveUpdateAPIView : RetrieveAPIView와 UpdateAPIView를 통합
- generics.RetrieveDestoryAPIView : RetrieveAPIView와 DestroyAPIView를 통합
- generics.RetrieveUpdateDestroyAPIView : RetrieveAPIView, UpdateAPIView, DestroyAPIView 통합
✔️ generics에서 제공하는 APIView를 사용하면 아래처럼 더 간결해진다. Mixins에 기능들을 이미 상속받고 있기 때문에 상속받을 generics class 조합으로 간단해졌고, 매서드도 따로 적어줄 필요가 없다.
from rest_framework import generics from fbvApp.models import Student from fbvApp.serializers import StudentSerializer class StudentList(generics.ListCreateAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer class StudentDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer
✔️ Generics의 코드를 살펴보면, queryset과 serializer_class가 반복되는게 보인다. 두개의 View를 하나로 합친다면 이를 해결할 수 있을 것이다.
✔️ 이를 가능하게해주는 것이 ViewSets이다. 아래코드 몇 줄로 위에 모든 기능이 가능해진다.
✔️ ViewSets를 이용하여 CRUD를 구현하기 위해 rest_framework의 viewsets을 상속받는다.
from rest_framework import viewsets # 👈 viewsets 가져오기 from fbvApp.models import Student from fbvApp.serializers import StudentSerializer class StudentViewSet(viewsets.ModelViewSet): queryset = Student.objects.all() serializer_class = StudentSerializer
✔️ viewsets 이용하기 전, CBV에서는 아래와 같이 urls.py를 작성하여 로직과 경로를 매핑해주었다.
from django.urls import path from . import views urlpatterns = [ path('students/', views.StudentList.as_view()), path('students/<int:pk>/', views.StudentDetail.as_view()), ]
✔️ Viewsets을 이용하면, URL 경로를 잡아주기 위해 router 설정을 해주어야한다.
✔️ 이를 위해 DefaultRouter를 import하고, 등록한 router를 rulpatterns를 통해 include 시켜줘야 한다.
✔️ 왜냐하면, listView 경우 pk가 필요없지만, DetialView의 3개 매서드(GET, PUT, DELETE)의 경우는 pk가 필요하기 때문이다.
from django.urls import path, include from . import views from rest_framework.routers import DefaultRouter # 👈 DefaultRouter 가져오기 router = DefaultRouter() # 👈 router 인스턴스 생성 router.register('students', views.StudentViewSet) # 👈 router에 ViewSet 등록 urlpatterns = [ path('', include(router.urls)) # 👈 router를 include를 통해 경로 매핑 ]