Django REST Framework/DRF 일반

[DRF] 공식 문서 - views의 정리 4 - CBV(Mixins)

bluebamus 2024. 1. 10.

 1. Mixins

   - mixin class들은 기본적인 view 동작을 제공하기 위해 사용되는 action들을 제공한다.

   - 주의해야 할 점은 mixin class들은 .get() 이나 .post()와 같은 handler method를 직접 정의하는 것이 아닌 action method를 제공하는 것이다.

   - 행위들의 좀 더 유연한 구성을 만들 수 있도록 한다.

   - rest_framework.mixins로부터 import해 사용할 수 있다.

 

   - APIview를 사속하는 경우와 GenericAPIview를 상속하는 경우의 차이

from rest_framework.mixins import RetrieveModelMixin
from rest_framework.response import Response
from rest_framework.views import APIView

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelRetrieveAPIView(RetrieveModelMixin, APIView):
    """
    A view for retrieving a single instance of YourModel using RetrieveModelMixin and APIView.
    """
    model = YourModel
    serializer_class = YourModelSerializer

 

   1) ListModelMixin

      - queryset을 나열할 수 있는 .list(request, *args, **kwargs) 메서드를 제공한다.
      - 만약 queryset의 내용이 존재한다면 200 OK response를 반환한다.
         - serialized된 queryset가 response의 body가 된다.
      - response data는 선택적으로 페이징될 수 있다.

 

      - APIview 사용시

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100

class YourAPIView(APIView):
    pagination_class = YourModelPagination

    def get(self, request, *args, **kwargs):
        # Step 1: Get the base queryset
        queryset = YourModel.objects.all()

        # Step 2: Apply any necessary filtering to the queryset
        queryset = self.filter_queryset(queryset)  # Using filter_queryset here

        # Step 3: Check if pagination is requested
        page = self.paginate_queryset(queryset)

        if page is not None:
            # Step 4a: If paginated, serialize the paginated data
            serializer = YourModelSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        else:
            # Step 4b: If not paginated, serialize the entire queryset
            serializer = YourModelSerializer(queryset, many=True)
            return Response(serializer.data)

 

      - GenericAPIView 사용시

from rest_framework.mixins import ListModelMixin
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100

class YourModelListView(ListModelMixin, GenericAPIView):
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer
    pagination_class = YourModelPagination  # Use your custom pagination class

    def get(self, request, *args, **kwargs):
        # Step 1: Get the base queryset
        queryset = self.get_queryset()

        # Step 2: Apply any necessary filtering to the queryset
        queryset = self.filter_queryset(queryset)

        # Step 3: Check if pagination is requested
        page = self.paginate_queryset(queryset)

        if page is not None:
            # Step 4a: If paginated, serialize the paginated data
            serializer = YourModelSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        else:
            # Step 4b: If not paginated, serialize the entire queryset
            serializer = YourModelSerializer(queryset, many=True)
            return Response(serializer.data)


   2) CreateModelMixin

      - 새로운 model instance를 생성하고 저장할 수 있는 .create(request, *args, **kwargs) 메서드를 제공한다.
      - 만약 object가 생성된다면 201 Created response를 반환한다.
         - serialized된 object가 response의 body가 된다.
      - 만약 표현에 url이 key name으로 포함되어 있다면, response의 Location header가 value 값과 같이 채워진다.
      - 만약 제공된 request data로 object 생성이 불가능하다면 400 Bad Request response가 error detail을 body로 가지고 반환된다.

from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response
from rest_framework.status import HTTP_201_CREATED, HTTP_400_BAD_REQUEST
from rest_framework.views import APIView

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelCreateView(CreateModelMixin, APIView):
    def post(self, request, *args, **kwargs):
        # Step 1: Deserialize the request data using the serializer
        serializer = YourModelSerializer(data=request.data)

        # Step 2: Validate the serializer data
        if serializer.is_valid():
            # Step 3: Save the validated data to create a new instance
            self.perform_create(serializer)

            # Step 4: Return a 201 Created response with the serialized representation
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=HTTP_201_CREATED, headers=headers)
        else:
            # Step 5: Return a 400 Bad Request response with the error details
            return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

    def perform_create(self, serializer):
        # Custom method to save the instance to the database
        serializer.save()

 

      - mixin이 status와 header 코드를 적절하게 정의를 해준다 때문에 생략할 수 있다.

from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response
from rest_framework.views import APIView

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelCreateView(CreateModelMixin, APIView):
    def post(self, request, *args, **kwargs):
        # Step 1: Deserialize the request data using the serializer
        serializer = YourModelSerializer(data=request.data)

        # Step 2: Validate the serializer data
        if serializer.is_valid():
            # Step 3: Save the validated data to create a new instance
            self.perform_create(serializer)

            # Step 4: Return a response with the serialized representation
            return Response(serializer.data)
        else:
            # Step 5: Return a response with the error details
            return Response(serializer.errors)
    
    def perform_create(self, serializer):
        # Custom method to save the instance to the database
        serializer.save()


   3) RetrieveModelMixin

      - 현재 존재하고 있는 model instacne를 검색해 response로 반환하는 .retrieve(request, *args, **kwargs) 메서드를 제공한다.
      - 만약 object가 검색된다면 200 OK response가 반환된다.
         - serialized된 object가 response의 body가 된다.
      - 검색되지 않는다면 404 Not Found를 반환한다.

from rest_framework.mixins import RetrieveModelMixin
from rest_framework.response import Response
from rest_framework.views import APIView

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelRetrieveAPIView(RetrieveModelMixin, APIView):
    """
    A view for retrieving a single instance of YourModel using RetrieveModelMixin and APIView.
    """
    model = YourModel
    serializer_class = YourModelSerializer


    4) UpdateModelMixin

      - 현재 존재하고 있는 model instance를 업데이트하고 저장할 수 있는 .update(request, *args, **kwargs) 메서드를 제공한다. -> PUT
      - 또한 update 메서드와 비슷하지만 모든 필드를 선택적으로 업데이트할 수 있는 .partial_update(request, *args, **kwargs) 메서드를 제공한다. -> PATCH
      - 만약 object의 업데이트에 성공한다면 200 OK를 반환한다.
          - serialized된 object가 response의 body가 된다.
      - 만약 object의 업데이트에 실패하게 되면 400 Bad Request response가 error detail을 body로 가지고 반환된다.

from rest_framework.mixins import UpdateModelMixin
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelUpdateAPIView(UpdateModelMixin, GenericAPIView):
    """
    A view for updating a single instance of YourModel using UpdateModelMixin and GenericAPIView.
    """
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer

    def put(self, request, *args, **kwargs):
        """
        Handle PUT requests to update a single instance of YourModel.
        """
        return self.update(request, *args, **kwargs)

    def perform_update(self, serializer):
        """
        Override this method to add custom logic when updating the model instance.
        This method is specific to UpdateModelMixin and may be used for any additional customization.
        By default, it saves the serializer.
        """
        # Example: Add custom logic before saving the instance
        serializer.save()


   5) DestroyModelMixin

      - 현재 존재하고 있는 model instance를 삭제하는 .destroy(request, *args, **kwargs) 메서드를 제공한다.
      - 만약 object가 성공적으로 삭제되면 204 No Content response를 반환한다.
      - 삭제에 실패한다면 404 Not Found를 반환한다.

from rest_framework.mixins import DestroyModelMixin
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

from .models import YourModel
from .serializers import YourModelSerializer

class YourModelDestroyAPIView(DestroyModelMixin, GenericAPIView):
    """
    A view for destroying a single instance of YourModel using DestroyModelMixin and GenericAPIView.
    """
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer

    def delete(self, request, *args, **kwargs):
        """
        Handle DELETE requests to destroy a single instance of YourModel.
        """
        return self.destroy(request, *args, **kwargs)

    def perform_destroy(self, instance):
        """
        Override this method to add custom logic when destroying the model instance.
        This method is specific to DestroyModelMixin and may be used for any additional customization.
        By default, it deletes the instance.
        """
        # Example: Add custom logic before deleting the instance
        instance.delete()

 

 - 공식 사이트 문서 : https://www.django-rest-framework.org/api-guide/generic-views/#mixins

 

 - reference : 

https://velog.io/@nikevapormax/Django-REST-frameworkMixins

 

Django REST framework_Mixins

Django REST framework Mixins

velog.io

댓글