brunch

매거진 백엔드

You can make anything
by writing

C.S.Lewis

by 내가 사는 세상 Nov 26. 2023

Django DRF - View

views.py에서 API 통신을 관리하는데 필요한 핵심 로직이 들어있다. 다양한 요청을 고객으로 받았을 때, 데이터를 가지고 어떻게 행동해야할지가 적여있는 것이다.



 다양한 요청이라고 하지만, 알고보면 고객이 요청하는 종류는 다음과 같이 정형화되어있다.



그래서 Djangdo REST Framework는 이를 표준화시켜 개발자가 이용하기 쉽게 잘 정리해두었다. 우리는 이를 가져다 쓰기만 하면 된다.




목차

FBV



CBV

1. APIView(기본형태)

2-1. MIXINS

2-2. GENERICS #MIXINS 조합

3. VIEWSET & ROUTERS



FBV


@api_view(['GET', 'POST'])

def mymodel_list(request):

    if request.method == 'GET':

        queryset = MyModel.objects.all()

        serializer = MyModelSerializer(queryset, many=True)

        return Response(serializer.data)


    elif request.method == 'POST':

        serializer = MyModelSerializer(data=request.data)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data, status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)




@api_view(['GET', 'PUT', 'PATCH', 'DELETE'])

def mymodel_detail(request, pk):

    try:

        instance = MyModel.objects.get(pk=pk)

    except MyModel.DoesNotExist:

        return Response(status=status.HTTP_404_NOT_FOUND)


    if request.method == 'GET':

        serializer = MyModelSerializer(instance)

        return Response(serializer.data)


    elif request.method == 'POST':

        serializer = MyModelSerializer(instance, data=request.data)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


    elif request.method == 'PUT':

        serializer = MyModelSerializer(instance, data=request.data)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


    elif request.method == 'PATCH':

        serializer = MyModelSerializer(instance, data=request.data, partial=True)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


    elif request.method == 'DELETE':

        instance.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)




CBV


1. APIView(기본형태)


가장 자유롭지만 자세히 코드를 작성해줘야 하는 것은 APIView이다.


from rest_framework.views import APIView

from rest_framework.response import Response

from rest_framework import status

from .models import YourModel

from .serializers import YourModelSerializer


class YourModelRetrieveUpdateDestroyAPIView(APIView):

    lookup_field = 'id'  # 여기서 'id'는 객체를 조회할 때 사용할 필드


    def get_object(self, pk):

        try:

            return YourModel.objects.get(id=pk)

        except YourModel.DoesNotExist:

            raise status.HTTP_404_NOT_FOUND


    def get(self, request, id, format=None):

        instance = self.get_object(id)

        serializer = YourModelSerializer(instance)

        return Response(serializer.data)


    def put(self, request, id, format=None):

        instance = self.get_object(id)

        serializer = YourModelSerializer(instance, data=request.data)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


    def patch(self, request, id, format=None):

        instance = self.get_object(id)

        serializer = YourModelSerializer(instance, data=request.data, partial=True)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


    def delete(self, request, id, format=None):

        instance = self.get_object(id)

        instance.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)


이 코드는 너무 길다. 중복되는 부분을 줄일 필요가 있다. 그렇게 mixins가 등장한다.



2-1. MIXINS


from rest_framework import generics

from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin

from .models import YourModel

from .serializers import YourModelSerializer


class YourModelRetrieveUpdateDestroyAPIView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, generics.GenericAPIView):

    queryset = YourModel.objects.all()

    serializer_class = YourModelSerializer

    lookup_field = 'id'  # 여기서 'id'는 객체를 조회할 때 사용할 필드


    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-2. GENERICS


generics는 mixins를 조합한 것에 불과하다. GenericAPIView의 기본 형태는 django-rest-framework/rest_framework/generics.py에서 살펴볼 수 있듯, 다음과 같다. 


class GenericAPIView(views.APIView):

    queryset = None

    serializer_class = None

 

    def get_object(self):

        어쩌고 저쩌고


    def post(self, request):

        어쩌고 저쩌고




이를 기반으로 mixin들의 조합은 9가지가 나오며, 이를 하나씩 보면 다음과 같다.


1. class CreateAPIView(mixins.CreateModelMixin, GenericAPIView):

: post(self, request, *args, **kwargs): →  create(self, request, *args, **kwargs):

: 전자는 CreateAPIView에 정의된 것이며, 후자를 CreateModelMixin에서 가져온 것



2. class ListAPIView(mixins.ListModelMixin, GenericAPIView): #전체 조회

: PostSerializer(instance=, many=True)

: get(self, request, *args, **kwargs): → list(self, request, *args, **kwargs):

: 전자는 ListAPIView에 정의된 것이며, 후자를 ListModelMixin에서 가져온 것



3. class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView): #1개 조회

: PostSerializer(instance=, many=False)

: get(self, request, *args, **kwargs): → retrieve(self, request, *args, **kwargs):



4. class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView):

: put(self, request, *args, **kwargs): → update(self, request, *args, **kwargs):

: patch(self, request, *args, **kwargs): → partial_update(self, request, *args, **kwargs):



5. class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView):

: delete(self, request, *args, **kwargs): → destroy(self, request, *args, **kwargs):



6. class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):



7. class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView):



8. class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView):



9. class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin,

mixins.DestroyModelMixin, GenericAPIView):




예제 코드를 보자


from rest_framework import generics

from .models import YourModel

from .serializers import YourModelSerializer


class YourModelRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):

    queryset = YourModel.objects.all()

    serializer_class = YourModelSerializer

    lookup_field = 'id'  # 여기서 'id'는 객체를 조회할 때 사용할 필드




3. VIEWSET & ROUTERS


아예 모든 요청 Method들을 합쳐서 한번에 이용할 수도 있다. 이를 Viewset이라고 부른다.


// views.py

from rest_framework import viewsets

from .models import YourModel

from .serializers import YourModelSerializer


class YourModelViewSet(viewsets.ModelViewSet):

    queryset = YourModel.objects.all()

    serializer_class = YourModelSerializer

    lookup_field = 'id'


다만 viewset을 쓸 땐 urls.py를 작성하는 방식이 달라진다. drf에서 제공하는 라우터를 urls.py에 등록해야하는 것이다.


// urls.py

from rest_framework.routers import DefaultRouter

from .views import YourModelViewSet


router = DefaultRouter()

router.register(r'yourmodel', YourModelViewSet, basename='yourmodel')

urlpatterns += router.urls




참고자료

DRF 공식문서 : https://www.django-rest-framework.org/api-guide/generic-views/

DRF 정리문서 : https://www.cdrf.co/



매거진의 이전글 Django DRF - Serializer
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari