GenericViewSet과 Mixin 조합으로 나만의 CRUD 로직 만들기

GenericViewSet은 기본 구조를 제공하고, Mixin은 개별 CRUD 기능을 담당함. 이 둘을 조합하면 명확하고 안전하며 유연한 맞춤형 ViewSet 제작 가능

ModelViewSet의 한계

  • 보안 문제: 모든 CRUD 기능 노출로 실수로 삭제 기능이 열릴 위험

  • 명확성 부족: ReadOnlyProductViewSet이 ProductViewSet보다 의도가 명확

  • 유연성 부족: 특정 기능만 선택적으로 허용하기 어려움

핵심 개념

GenericViewSet

  • viewsets.ViewSetMixin과 generics.GenericAPIView를 상속

  • get_queryset(), get_object(), get_serializer() 등 기반 기능만 제공

  • 실제 액션 메서드(list, create 등)는 포함하지 않음

  • API의 기본 구조 제공

Mixin 종류

Mixin
액션 메서드
HTTP 메서드
설명

ListModelMixin

list()

GET

목록 조회

CreateModelMixin

create()

POST

객체 생성

RetrieveModelMixin

retrieve()

GET

단일 객체 조회

UpdateModelMixin

update()

PUT, PATCH

객체 수정

DestroyModelMixin

destroy()

DELETE

객체 삭제

조합 패턴

읽기 전용 ViewSet

class ProductReadOnlyViewSet(mixins.ListModelMixin,
                             mixins.RetrieveModelMixin,
                             viewsets.GenericViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

생성 가능하지만 수정/삭제 불가 ViewSet

class SurveyResponseViewSet(mixins.ListModelMixin,
                            mixins.RetrieveModelMixin,
                            mixins.CreateModelMixin,
                            viewsets.GenericViewSet):
    serializer_class = SurveyResponseSerializer
    permission_classes = [IsAuthenticated]

실무 팁

커스텀 Mixin 생성

class SoftDeleteModelMixin:
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        instance.is_deleted = True
        instance.save()
        return Response(status=status.HTTP_204_NO_CONTENT)

프로젝트 공통 BaseViewSet

class BaseViewSet(viewsets.GenericViewSet):
    permission_classes = [IsAuthenticated]
    pagination_class = MyCustomPagination

주의사항

  • 상속 순서(MRO) 중요: 구체적인 클래스를 왼쪽에, 일반적인 클래스를 오른쪽에 배치

  • ModelViewSet은 모든 Mixin을 포함한 완전한 CRUD ViewSet

Last updated