본문 바로가기
Python/Django

[DRF] GenericAPIView와 Mixins

by 코드뭉치 2023. 6. 7.

DRF에서는 GenericAPIView와 다양한 Mixin 클래스를 결합해 APIView를 구현할 수 있다.

 

1️⃣ GenericAPIView

 

GenericAPIView는 queryset과 serializer_class를 지정해줄 수 있다.

  • queryset - View에서 객체를 반환하는 데 사용할 Queryset.
    일반적으로 queryset을 설정하거나 get_queryset() 메서드를 오버라이딩 해야함.
  • serializer_class - 입력의 Validation Deserialize, 출력의 Serialize에 사용하는 serializer
    일반적으로 Serializer를 설정하거나 get_serializer_class() 메서드를 오버라이딩 해야함.

 

APIView와 비교

# APIView 사용
class ArticleListView(APIView):
    def get(self, request, *args, **kwargs):
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)

    def post(self, request, *args, **kwargs):
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)
        
        
# GenericAPIView 사용
class ArticleListGenericView(GenericAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    def get(self, request, *args, **kwargs):
        articles = self.get_queryset()
        serializer = self.get_serializer(articles, many=True)
        return Response(serializer.data)

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)

 

GenericAPIView 사용만으로는 일반적인 APIView 사용에 비해서 드라마틱한 변화를 보여주지는 않는다.

따라서 여러가지 Mixin들을 함께 사용하게 된다.

 

예를들어, ListModelMixin과 CreateModelMixin을 사용하면 더욱 간결하게 코드를 작성할 수 있다.


2️⃣ Mixins

 

View에서 항상 써주던 반복적인 코드들을 간결하게 만들어주는 녀석

 

각각의 Mixin들은(특히 Update와 Create) 특정 메소드를 작성해줄 필요가 있다.(.create() 혹은 .update 등)

Serializer를 ModelSerializer를 상속받아 사용한다면 해당 메소드들을 기본적으로 제공해주기 때문에,

직접 작성해줄 것이 아니라면 ModelSerializer를 사용하는 것이 좋다.

 

ListModelMixin과 CreateModelMixin을 사용한 예시

* 각각 list()와 create() 메소드를 사용하여, 조회와 생성을 해줌

 

class ArticleView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

 

이처럼 Mixin과 GenericAPIView를 같이 사용하면 코드를 정말 깔끔하게 짤 수 있다.

 

 

주요 Mixin들은 아래와 같다.

 

- ListModelMixin

  • Queryset의 객체 목록을 보여줌 (GET)
  • .list(request, *args, **kwargs)메소드로 사용
  • 성공 시, 200 OK

 

- CreateModelMixin

  • 객체를 생성하고 저장 (CREATE)
  • .create(request, *args, **kwargs)메소드로 사용
  • 성공 시, 200 OK
  • 실패 시, 400 Bad Request

 

- RetrieveModelMixin

  • 객체를 반환 (GET)
  • .retrieve(request, *args, **kwargs) 메소드로 사용
  • 성공 시, 200 OK
  • 실패 시, 404 Not Found

 

- UpdateModelMixin

  • 객체를 수정 후 저장 (UPDATE)
  • .update(request, *args, **kwargs) 메소드로 사용
  • .partial_update(request, *args, **kwargs)메소드로 PATCH도 가능
  • 성공 시, 200 OK
  • 실패 시, 404 Not Found

 

- DestroyModelMixin

  • 객체를 삭제 (DELETE)
  • .destroy(request, *args, **kwargs) 메소드로 사용
  • 성공 시, 204 No Content
  • 실패 시, 404 Not Found

 

예시) 상세조회, 수정, 삭제

class ArticleDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    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)

 

코드가 정말 깔끔해졌다.

그런데 여기서 한가지 불편한 점이 있다.

 

첫번째로, 상속 받는 부분이 너무 길고, 불편하다.

두번째, 여전히 각각의 method별로 정의해줘야 한다.

 

하지만 우리의 Django "Rest" Framework는 이것마저도 다 만들어져있다.


3️⃣ Concrete View Classes

from rest_framework import generics

 

rest_framework의 generics에는 9개의 View가 준비되어 있다.

 

  • CreateAPIView
  • ListAPIView
  • RetrieveAPIView
  • DestroyAPIView
  • UpdateAPIView
  • ListCreateAPIView
  • RetrieveUpdateAPIView
  • RetrieveDestroyAPIView
  • RetrieveUpdateDestroyAPIView

각각의 View들은 이름과 같은 ModelMixin과 GenericAPIView를 상속한 것들이다.

예를 들어 ListCreateAPIView는 List,Create관련 Mixin과 GenericAPIView를 상속하고,

자체적으로 get과 post 메소드가 정의되어 있다.

 

class ListCreateAPIView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        GenericAPIView):
    """
    Concrete view for listing a queryset or creating a model instance.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

 

RetrieveUpdateAPIView는 GenericAPIView, RetrieveModelMixin, UpdateModelMixin을 상속.

get, put, patch 메소드를 가지고 있다.

 

class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
                            mixins.UpdateModelMixin,
                            GenericAPIView):
    """
    Concrete view for retrieving, updating a model instance.
    """
    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)

 

여기까지 모두 이해했다면, 처음의 코드를 아래와 같이 만들어 줄 수 있다.

 

class ArticleListGenericView(ListCreateAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
class ArticleDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

 

import 제외 6줄의 코드로 하나의 모델에 대해서 

  • 전체 목록 조회
  • 모델 생성
  • 특정 모델 조회
  • 특정 모델 수정
  • 특정 모델 일부 수정
  • 특정 모델 삭제

에 해당하는 기능을 모두 해줄 수 있는 것이다.

 

 

 

* 원하는 APIView가 없다면 여기를 참고해 커스텀 View를 작성해 줄 수도 있다.

댓글