FrameWork/Django

DRF FBV, CBV (APIView, Mixin, Generic, Viewset)

jheaon 2023. 8. 28. 03:56

 

DRF에서 뷰를 나타내기 위해서는 2가지의 방법이 있는데 하나는 함수 기반 뷰(Function Base View)와 다른 하나는 클래스 기반 뷰 CBA(Class Base View)가 있습니다. 

 

기본 속성

함수 기반 뷰와 클래스 기반 뷰를 다루기전에 둘이 공통적으로 제공하는 속성 값이 있는데 아래와 같습니다. 

renderer_classes (직렬화 클래스) - JSON 직렬화 : rest_framework.renderers.JSONRenderer
- HTML 직렬화 : rest_framework.renderers.TemplateHTMLRenderer
parser_classes (비직렬화 클래스) - JSON 포맷 처리 :rest_framework.parsers.JSONParser
- FormParser :rest_framework.parsers.FormParser
- MultiPartParser :rest_framework.MultiPartParser
authentication_classes (인증 클래스) - 세션에 기반한 인증 :rest_framework.authentication.SessionAuthentication
- HTTP Basic 인증 :rest_framework.authentication.BasicAuthentication
throttle_classes (사용량 제한 클래스) - 빈튜플
permission_classes (권한 클래스) - 누구라도 접근 허용 :rest_framework.permissions.AllowAny
content_negotiation_class (요청에 따라 적절한 직렬화/비직렬화 선택) - rest_framework.negotiation.DefaultContentNegotiation
metadata_class - rest_framework.metadata.SimpleMetadata
versioning_class (요청 내역에서 API 버전 정보를 탐지할 클래스) - None : API 버전 정보를 탐지하지 않겠다.

 

함수 기반 뷰 (FBV)

DRF에서 함수기반 뷰로 작성할 경우에는 api_view 장식자를 이용하여 처리합니다.  일반적으로 api_view() 안에 허용하는 http method을 리스트 형태로 받아 작성하고 만약 () 안에 http method가 없다면, get 요청만 허용합니다. 

 

🖥️ views.py

from rest_framework.decorators import api_view
from rest_framework.response import Response

from .models import Post
from .serializers import PostSerializer


@api_view()
def hello_world(request):
    return Response({"message": "Hello, world!"})

@api_view(['GET', 'POST'])
def hello_world(request):
    if request.method == 'POST':
        return Response({"message": "Got some data!", "data": request.data})
    return Response({"message": "Hello, world!"})
    
@api_view(['GET', 'POST'])
def post_list(request):
	if request.method == 'GET':
 		qs = Post.objects.all()
  		serializer = PostSerializer(qs, many=True)
		return Response(serializer.data)
 	elif request.method == 'POST':
 		serializer = PostSerializer(data=request.data)
   		if serializer.is_valid():
  			serializer.save()
 			return Response(serializer.data, status=201)
 		return Response(serializer.errors, status=400)

@api_view(['GET','PUT','DELETE'])
def post_detail(request, pk):
	post = get_object_or_404(Post, pk=pk)
	if request.method == 'GET':
   		serializer = PostSerializer(post)
  		return Response(serializer.data)
	elif request.method == 'PUT':
		serializer = PostSerializer(post, data=reqeust.data)
 		if serializer.is_valid():
			serializer.save()
			return Response(serializer.data)
		return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
	elif request.method == 'DELETE'
  		post.delete()
 		return Response(status=status.HTTP_204_NO_CONTENT)

 

 앞서 말한 기본 속성을 변경하기 위해서는 @api_view 장식자 아래 장식자를 추가하여 설정할 수 있습니다.

  • @renderer_classes(...)
  • @parser_classes(...)
  • @authentication_classes(...)
  • @throttle_classes(...)
  • @permission_classes(...)

 

 

 

 

클래스 기반 뷰 (CBV)

DRF에서는 여러 가지 클래스 기반 뷰가 존재합니다.

왼쪽에서 오른쪽으로는 상속받아 사용되는 클래스의 크기를 의미합니다. (APIView < minxins < generics APIView < Viewset)

 

APIView

APIView를 상속하여 view을 설계하게 된다면, 개발자가 직접 해당 액션에 대해 Response와 status을 명시해주어야 합니다. 기존의 FBV 방식의 view 설계와 비슷하며 클래스 내의 메서드 명은 http method의 이름에 따라지어 줍니다.

 

🖥️ views.py

from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Post
from .serializers import PostSerializer

""" list / create """
class PostListAPIView(APIView):
	def get(self, request):	
		serializer = PostSerializer(Post.objects.all(), many=True)
  		return Response(serializer.data)
	def post(self, request):
 		serializer = PostSerializer(data=request.data)
  		if serializer.is_valid():
   			serializer.save()
   			return Response(serializer.data, status=201)
   		return Response(serializer.erros, status=400)

 

 

Mixins

Mixins은 APIView에서 method동작 로직이 모든 클래스에서 비슷한 역할을 수행하는 것을 간소화시킨 클래스입니다. 아래는 역할에 따른 Mixin의 종류입니다. 

  • CreateModelMixin
  • ListModelMixin
  • RetrieveModelMixin
  • UpdataModelMixin
  • DestroyModelMixin

 

🖥️ 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)
        
	def put(self, request, *args, **kwargs):
		return self.update(request)
        
	def delete(self, request, *args, **kwargs):
		return self.delete(request)

 

 

 

 

Generis APIView

Mixins을 상속함으로써 반복되는 내용을 많이 줄였으나 각 request method을 연결해줘야 하는 번거로움은 해결되지 않았습니다. 따라서 이런 문제점을 해결하기 위해 하나 이상의 Mixins와 결합된 클래스인 generics APIVivew 클래스가 만들어졌습니다. 

 

아래는 역할에 따른 generics APIView의 종류입니다. 

 

  • generics.CreateAPIView : 생성
  • generics.ListAPIView : 목록
  • generics.RetrieveAPIView : 조회
  • generics.DestroyAPIView : 삭제
  • generics.UpdateAPIView : 수정
  • generics.RetrieveUpdateAPIView : 조회 / 수정
  • generics.RetrieveDestroyAPIView : 조회 / 삭제
  • generics.ListCreateAPIView : 목록 / 생성
  • generics.RetrieveUpdateDestroyAPIView : 조회 / 수정 / 삭제

 

🖥️ 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

 

 

 

ViewSet

ViewSet은 2개의 URL별로 구현된 5개의 메서드를 하나의 단일 클래스로 제공합니다. 하나의 헬퍼클래스로 두 개 이상의 URL 처리가 가능합니다. 아래는 ViewSet의 클래스 종류입니다.

  • viewsets.ReadOnlyModelViewSet : list, detail 지원
  • viewsets.ModelViewSet : list / create 지원, detail / update / partial_update / delete 지원

 

- views.py

from .models import Post
from .serializers import PostSerializer
from rest_framework import viewsets

class PostViewSet(viewsets.ModelViewSet):
	queryset = Post.objects.all()
	serializer_class = PostSerializer

 

참고로 ViewSet을 이용하여 URL을 매핑하는 방법에는 개별로 등록하는 방법과 Router을 이용하여 등록하는 방법 즉 2가지가 있습니다.

 

  • 개별로 등록하는 방법

- urls.py

post_list = PostViewSet.as_view({
    'get': 'list',
})
post_detail = PostViewSet.as_view({
    'get': 'retrieve',
})

# urls에 직접 path 작성해야 함

 

  • Router을 이용하여 등록하는 방법 : 라우터를 등록해주어야 합니다. 

- urls.py

from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('post', views.PostViewSet)

urlpatterns = [
	path('', include(router.urls)),
]

 

 


참조 :

 

https://velog.io/@duo22088/DRF-APIView-Mixins-generics-APIView-ViewSet-%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C

 

(DRF) APIView, Mixins, generics APIView, ViewSet 에 대해서

상황에 맞춰 다향한 방법으로 View 를 구현하여 생산성을 극대화 시켜 봅시다.

velog.io

https://joel-dev.site/68

 

[DRF] 2. APIView / Mixins / Generic CBV

안녕하세요! 파피몬입니다! ✨ 백엔드 API 서버가 어떻게 구축되는지 조금 알 필요가 있다고 생각이 들어서 Django Rest Framework(이하 DRF)를 공부하고 있습니다. 아직 개발자를 지망하는 학생입니다!

joel-dev.site

https://www.cdrf.co/

 

Django REST Framework 3.14 -- Classy DRF

What is this? Django REST framework is a powerful and flexible toolkit that makes it easy to build Web APIs. It provides class based generic API views and serializers. We've taken all the attributes and methods that every view/serializer defines or inherit

www.cdrf.co

https://www.django-rest-framework.org/

 

Home - Django REST framework

 

www.django-rest-framework.org

 

'FrameWork/Django'의 다른글

  • 현재글 DRF FBV, CBV (APIView, Mixin, Generic, Viewset)

관련글