mixins 상속을 통한 generics의 APIView

최동혁·2022년 12월 10일
0

DRF

목록 보기
6/19

DRF에서 지원하는 mixins

CreateModelMixin

ListModelMixin

RetrieveModelMixin

UpdateModelMixin

DestroyModelMixin

mixin이란?

  • 실제로 직접적으로 사용되는것이 아닌, 다른 클래스에 의해 상속이 이루어질때 사용이 되는 모듈들을 의미있는 단어로 구현해 놓은 것이다.

일반적인 메소드

  1. List -> get/post
  2. Detail -> get/(put이나 patch)/ delete
  • 총 5개의 메소드가 위의 mixin들에 매칭이 되는 것이다.

CreateModelMixin -> List의 post
ListModelMixin -> List의 get
RetrieveModelMixin -> Detail의 get
UpdateModelMixin -> Detail의 put이나 patch
DestoryModelMixin -> Detail의 delete

CreateModelMixin

class CreateModelMixin:
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}
  • 실제 create라는 함수가 있다.
  • 유효성 검사를 했을 때, 통과가 안되면 다음 줄 실행 불가능하다.
    • drf mixin에서는 form과 다르게 true 혹은 false 반환이 아닌, 예외 방식으로 처리해준다.
  • perform create는 save()를 이용해 db에 저장해준다.
  • get_success_headers는 성공했을때 응답 헤더에 넣어줄 헤더 목록을 받아와서 Response를 리턴해준다.
  • mixin에는 어떤 http method가 왔을 때, create를 호출하겠다 라는 로직이 여기에는 없다.

예시) method별 로직 연결 (1/2)

from rest_framework import generics
from rest_framework import mixins

class PostListAPIView(mixins.ListModelMixin, mixins.CreateModelMixin,
generics.GenericAPIView):
  queryset = Post.objects.all()
  serializer_class = PostSerializer
  
  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를 상속 받을때에는 무조건 가장 뒤에 와야 한다.

  • 상속으로 ListModelMixin과 CreateModelMixin을 받았다.

    ListModelMixin을 통해 list라는 멤버함수가 생긴다.
    CreateModelMixin을 통해 create라는 멤버함수가 생긴다.

  • 그래서 해당 코드에 self.list와 self.create가 상속을 받아서 생기는 멤버함수이다.

  • 위에서 말했듯이, mixin 클래스 내에서는 해당 http 메소드에 맞게 매핑해주는 로직이 없다.

  • 그렇기 때문에 위의 코드처럼 직접 매핑 시켜줘야한다.

  • 인자들을 받은 그대로 넘겨줘야하는데, 매번 이렇게 연결해주려니 너무 불편하다.

  • 다음 예시도 보자.

예시) method별 로직 연결 (2/2)

from rest_framework import generics
from rest_framework import mixins

class PostDetailAPIView(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.destroy(request, *args, **kwargs)
  • 이것도 마찬가지로 각 mixin을 상속 받은 것에 맞는 멤버함수들이 생긴다.

    RetrieveModelMixin -> retrieve
    UpdateModelMixin -> update
    DestroyModelMixin -> delete

  • 이것도 매번 매핑 시켜주기 번거롭다.

패턴화 해놓은것

  • APIView에서 일반적인 로직들을 섞어서 mixins로 재사용성을 높인것.
  • mixins에서 패턴화해서 정리한것이 Generics이다.
  • Generics를 좀 더 정리한 것이 Viewset이다.

여러 generics APIView (모두 GenericsAPIView 상속)

  • generics.CreateAPIView : post -> create
  • generics.ListAPIView : get -> list
  • generics.RetrieveAPIView : get -> retrieve
  • generics.DestroyAPIView : delete -> destroy
  • generics.UpdateAPIView : put -> update, patch -> partial_update
  • generics.ListCreateAPIView : get -> list, post -> create
  • generics.RetrieveUpdateAPIView : get -> retrieve, put -> update, patch -> partial_update
  • generics.RetrieveDestroyAPIView : get -> retrieve, delete -> destroy
  • generics.RetrieveUpdateDestroyAPIView
    : get -> retrieve, put -> update, patch -> partial_update, delete -> destroy

결국 generics와 mixin은?

  • generics는 결국 mixins을 상속 받은것임.
  • mixins를 썻다면 post -> create, get -> list 같이 http 메소드에 맞게 하나하나 함수들을 매핑을 해야함.
  • generics는 mixins을 상속 받아서 이 매핑들을 다 해준것임.

generic APIView 활용 (1/2)

from rest_framework import generics

class PostListAPIView(generics.ListCreateAPIView):
  queryset = Post.objects.all()
  serializer_class = PostSerializer
  • generics의 ListCreateAPIView를 활용하면 엄청나게 쉬워진다.
  • 아래 코드는 ListCreateAPIView의 코드이다.
# 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)
  • mixins는 http 메소드 별로 매핑이 되어있지 않고 내부 로직만 짜여져있는데, generics는 mixins를 상속 받아서 매핑을 다 해놓았다.

generic APIView 활용 (2/2)

from rest_framework import generics

class PostDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
  queryset = Post.objects.all()
  serializer_class = PostSerializer
# rest_framework/generics.py
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
								mixins.UpdateModelMixin, 											mixins.DestroyModelMixin,
								GenericAPIView):
                                
  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 patch(self, request, *args, **kwargs):
  	return self.partial_update(request, *args, **kwargs)
  
  def delete(self, request, *args, **kwargs):
  	return self.destroy(request, *args, **kwargs)

다양한 View의 구현 방법 -> 중복을 줄이기

상황에 맞춰 다양한 방법으로 View를 구현하여, 생산선을 극대화 하자!

다양한 ViewSet(다음 포스트)

다양한 APIView, @api_view

다양한 장고 View

profile
항상 성장하는 개발자 최동혁입니다.

0개의 댓글