mixins 상속을 통한 APIView 로직 재사용

guava·2022년 1월 14일
0

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 강의를 듣고 정리한 글입니다.

1. mixins 상속을 통한 APIView


1.1. DRF에서 지원하는 mixins

필요에 의해 다양한 믹스인을 만드실 수 있어요.

https://github.com/encode/django-rest-framework/blob/3.11.0/rest_framework/mixins.py

파이썬 클래스의 상속문법이 이용되어 구현된다.

믹스인 클래스는 직접적으로 사용되는게 아니라 다른 클래스에 의해서 상속이 이루어 지며 사용된다.

로직만 구현되어 있을 뿐, 실제 http method와 연계하는 부분은 우리가 따로 연결해줘야 한다.

  • CreateModelMixin : Create를 하는 일반적인 로직이 구현되어 있음.
  • ListModelMixin : 목록을 조회하는 로직
  • RetrieveModelMixin
  • UpdateModelMixin
  • DestroyModelMixin

CreateModelMixin

# https://github.com/encode/django-rest-framework/blob/3.11.0/rest_framework/mixins.py#L12
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)  # 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 {}

1.2. method별 로직 연결

from rest_framework import generics
from rest_framework import mixins
class PostListAPIView(**mixins.ListModelMixin**, **mixins.CreateModelMixin**, generics.GenericAPIView):  # generics.GenericAPIView가 가장 마지막에 상속받아야 한다.
    queryset = Post.objects.all()
    serializer_class = PostSerializer

    def get(self, request, *args, **kwargs):  # get일 때, self.list를 호출하겠다라고 매핑
        return **self.list**(request, *args, **kwargs)  # mixins.ListModelMixin을 상속받아서 사용 가능

    def post(self, request, *args, **kwargs):  # post일 때 self.create를 호출하겠다라고 매핑
        return **self.create**(request, *args, **kwargs) # mixins.CreateModelMixin을 상속받아서 사용 가능

"""get -> self.list, post -> self.create를 매번 같은 파라미터를 넘겨 연결하려니 번거롭다."""
from rest_framework import generics
from rest_framework import mixins
class PostDetailAPIView(**mixins.RetrieveModelMixin**, **mixins.UpdateModelMixin**, **mixins.DestroyModelMixin**, generics.GenericAPIView):  # 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)

"""마찬가지로 매번 연결하려니 번거롭다. 심지어 하나가 늘어남.."""

⇒매번 연결하는 부분을 패턴화 해서 정리한 것이 Generics이다.

View 구현 시 상속받는 클래스의 추상화 정도: APIView < mixins < Generics < ViewSet

  • mixins : APIView에서 일반적인 로직들을 섞어서 재사용성을 높인 것
  • Generics : mixins 사용을 패턴화해서 정리함
  • ViewSet : Generics를 한번 더 합쳐서 정리

1.3. 여러 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

https://github.com/encode/django-rest-framework/blob/3.11.0/rest_framework/generics.py

1.4. APIView 활용

직접 http메소드와 로직을 연결하지 않고, 이미 연결되어있는 클래스를 상속받아 사용한다.

"""generics.ListCreateAPIView를 상속받아서 post list view를 구현"""
from rest_framework import generics
class PostListAPIView(generics.ListCreateAPIView):  # 아래 ListCreateAPIView를 상속
    queryset = Post.objects.all()
    serializer_class = PostSerializer

# 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)
"""generics.RetrieveUpdateDestroyAPIVie를 상속받아서 post detail view를 구현"""

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)

2. 정리


  • 믹스인에는 create(), list() 등의 리소스를 생성하거나 가져오는 로직이 구현되어 있다.
  • APIView와 mixin을 상속받아서 메소드별(get(), post() 등) 로직을 재정의해서 mixin의 함수(list(), create() 등)를 매핑할 수 있다. 이러한 구현체가 generics의 여러 APIView들이다. (LisrCreateAPIView 등)
  • 직접 APIView를 기반으로 여러 믹스인과 조합해보면서 사용해보는것도 괜찮은 학습 방법이다.

0개의 댓글