오늘도 개발

Django Rest Framework 튜토리얼 따라하기 2. view 쉽게 작성하기 본문

웹 프로그래밍/Django

Django Rest Framework 튜토리얼 따라하기 2. view 쉽게 작성하기

Sueeeeeee 2023. 1. 8. 00:52

1. DRF에서 제공하는 Request, Response, Status code

Request 오브젝트

django의 HttpRequest 오브젝트를 확장한 것.

좀 더 유연하게 데이터를 다룰 수 있는 data() 메서드를 제공한다.

# django의 HttpRequest에서 나온 오브젝트. POST 메서드의 form 데이터만 다룰 수 있다.
request.POST

# drf의 Request에서 나온 오브젝트. POST, PUT, PATCH 메서드까지 다룰 수 있다.
request.data

 

Response 오브젝트

클라이언트가 요청한 content type대로 데이터를 렌더링해준다.

return Response(data)

 

status codes

상태 코드를 더 정확하게 사용할 수 있게 숫자에 설명을 더한 identifier를 제공한다.

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

 

2. DRF의 api view

아래 두 가지 방법을 사용하면 view에서 Request와 Response 오브젝트를 사용할 수 있다.

 

1. @api_view 데코레이터 추가

from rest_framework import status 
from rest_framework.decorators import api_view 
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

@api_view(['GET', 'POST'])
# format=None을 붙이고, urls.py에 설정을 추가하면 클라이언트 요청에 맞는 형식으로 데이터를 응답할 수 있다.
def snippet_list(request, format=None):
    if request.method == "GET":
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        # Response 오브젝트를 사용할 수 있다.
        return Response(serializer.data)

    if request.method == "POST":
        # @api_view를 사용하기 전 작성했던 아래 코드는 이제 명시할 필요가 없다.
        # data = JSONParser().parse(request)
        # 바로 request.data로 사용할 수 있다.
        serializer = SnippetSerializer(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', 'DELETE'])
def snippet_detail(request, pk, format=None):
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == "GET":
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    elif request.method == "PUT":
        serializer = SnippetSerializer(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 == "DELETE":
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

 

2. APIView 클래스 상속

데코레이터보다 더 코드 반복을 줄일 수 있는 방법.

from django.http import Http404 
from rest_framework.views import APIView 
from rest_framework.response import Response 
from rest_framework import status

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

class SnippetList(APIView):
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(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)

class SnippetDetail(APIView):
    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            return Http404

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data) 

    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    def delete(self, request, pk, format=None):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

 

 

3. DRF의 mixin 사용하기

mixin은 자주 사용하는 create, retrieve, update, delete 작업을 구현해둔 클래스이다.

mixin 클래스를 상속받으면 더 간단하게 view를 작성할 수 있다.

예를 들어 ListModelMixin은 여러 오브젝트를 응답하는 list 메서드를,

RetrieveModelMixin은 한 오브젝트를 응답하는 retrieve 메서드를 갖는다. 

 

generics.GenericAPIView는 기본적인 APIView이다.

mixin 클래스를 사용할 때 함께 같이 사용해야 한다.

from rest_framework import mixins
from rest_framework import generics

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

class SnippetList(mixins.ListModelMixin, 
                  mixins.CreateModelMixin, 
                  generics.GenericAPIView):

    # SnippetList에서 사용할 queryset과 serializer_class를 DRF에게 알려줌
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    '''
    위의 코드는 아래 코드와 같은 일을 함
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)
    '''

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
    '''
    def post(self, request, format=None):
        serializer = SnippetSerializer(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)
    '''

class SnippetDetail(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):

    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    '''
    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data) 
    '''

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    '''
    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    '''

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
    '''
    def delete(self, request, pk, format=None):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    '''

generic.GenericAPIView와 mixin을 합친 ListAPIView, RetrieveAPIView 등도 있다.