Django, DRF에서도 함수 기반 뷰(FBV), 클래스 기반 뷰(CBV)로 개발할 수 있다. 뷰 작성할 떄의 함수/클래스 차이일 뿐 기능 차이는 없다.

FBV/CBV 공통적으로 사용하는 APIView wrapper가 있는데, 요청에 유형에 따라 동작할 수 있게 도와준다.

뷰에서 Request 인스턴스를 수신하고, 해당 메소드를 인자로 전달해서 해당 메소드에 맞는 로직이 실행되도록 도오하준다. @api_view는 클래스형 뷰의 as_view()처럼 여러가지 메소드를 처리하도록 도와준다고 보면 된다.

FBV CBV
데코레이터로 작성 @api_view 클래스를 상속하는 형태

Request와 Response

DRF에서 HTTP 요청 객체로 HttpRequest 객체를 확장한 Request 객체를 사용한다. 자주 사용하는 Request 속성은 다음과 같다.

  • Request Parsing
    • request.data : (POST, PUT, PATCH메소드에서) Body에 담겨 전달된 데이터를 리턴 (key:value)
    • request.query_params : 쿼리스트링으로 전달되는 데이터를 리턴 (key:value)
  • Request Authentication
    • request.user : django.contrib.auth.models.User의 객체를 리턴
    • request.auth : 해당 객체의 token를 리턴 (없다면, None을 리턴)
  • Browser enhancements
    • request.method : request의 메소드를 리턴
    • request.content_type : request의 컨텐트타입을 리턴

[request.POST]와 [request.data]의 차이점

request.POST  # 폼 데이터만 처리할 수 있고, POST 메소드에서만 동작한다.
request.data  # 임의의 데이터를 처리할 수 있고, POST, PUT, PATCH 메소드에서 동작한다.

Response

렌더링되지 않은 내용을 읽어서 클라이언트가 요청한 콘텐츠 타입에 맞는 형식으로 렌더링해준다. Django에서는 전달할 데이터에 따라 HttpResponse, JsonResponse를 개발자가 직접 지정을 해 주어야 하지만, DRF의 Response를 이용하면 알아서 렌더링 해준다.

# Signature
Response(data, status=None, template_name=None, headers=None, content_type=None)

# use case
return Response(data, status.HTTP_201_CREATED)

status

REST Framework에서는 status 모듈 안에 각각의 상태정보를 속성으로 담고 있다. 따라서 status.[상태 속성값]을 호출하면 그에 맞는 상태 값이 전달된다.

대표적인 상태 코드는 다음과 같다.

status.HTTP_200_OK # 정상 응답
status.HTTP_201_CREATED # 데이터 생성 정상 응답
status.HTTP_206_PARTIAL_CONTENT # 데이터 수정 정상 응답
status.HTTP_400_BAD_REQUEST # 잘못된 요청
status.HTTP_401_UNAUTHORIZED # 인증 X
status.HTTP_403_FORBIDDEN # 접근하지 못하도록 막은 곳에 요청 왔을때 응답
status.HTTP_404_NOT_FOUND # 잘못된 URL 응답
stauts.HTTP_500_INTERNAL_SERVER_ERROR # 서버 코드가 잘못되었을 때 응답

Function-based view 와 Class-based view

from rest_framework import viewset, permission, generics, status
from rest_framework.response import Response
from rest_framework.view import APIView
from rest_framework.decorators import api_view

# 함수형 뷰 FBV
@api_view(['GET'])
def HelloAPI(request):
    return Response("hello world")

# 함수형 뷰 FBV   
@api_view(["GET", "POST"])
def booksAPI(request):
    if request.method == "GET":
        books       = Book.objects.all() # 모델로부터 전체 데이터 가져오기
        # 시리얼라이저에 전체 데이터를 한번에 넣기, 직렬화 many=True
        serializer  = BookSerializer(books, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
    
    elif request.method == "POST":
        serializer  = BookSerializer(data=request.data)
        if serializer.is_valid(): # 시리얼라이저에서 기본적으로 validation을 지원함
            serializer.save() # create() 동작
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        
    return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)

@api_view(["GET"])
def bookAPI(request, bid): # /book/bid/
    # bid = id인 데이터를 Book에서 가져오고, 없으면 404 에러
    book        = get_object_or_404(Book, bid=bid) 
    serializer  = BookSerializer(book)
    return Response(serializer.data, status=status.HTTP_200_OK)    


# 클래스 뷰
class HelloAPI(APIView):
    def get(self, request):
        return Response("hello world")

class BooksAPI(APIView):
    def get(self, request):
        books = Book.objects.all()
        serializer  = BookSerializer(books, many=True) # 직렬화 many=True
        return Response(serializer.data, status=status.HTTP_200_OK)
    
    def post(self, request):
        serializer  = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)    

class BookAPI(APIView):
    def get(self, request, bid):
        book        = get_object_or_404(Book, bid=id)
        serializer  = BookSerializer(book)
        return Response(serializer.data, status=status.HTTP_200_OK)
  1. get_object_or_404() : 모델 객체가 존재하지 않을때, get()을 사용하여 404 예외 처리를 발생시킴

APIView

REST 프레임워크는 Django View 클래스의 하위클래스로 APIView 클래스를 제공한다. APIView 클래스와 View클래스의 다른점은 다음과 같다.

  • Request는 Django의 HttpRequest 인스턴스가 아닌 REST 프레임워크의 request 인스턴스가 됨
  • DJango의 HttpResponse가 아닌 REST 프레임워크의 Response를 반환
  • APIException 예외 케이스가 나오면 적절한 response으로 조정
  • incoming request를 auth하고, 적절한 권한및 사항을 체크한 뒤 실행

정리하자면

  1. 엔드포인트 숫자, 역할 및 결과물 동일함
  2. FBV에서 하나의 View에서 if request.method로 분리(GET/POST 등)한다면, CBV에서는 def get/post 등으로 명시함
  3. FBV에서는 try/except로 특정 객체가 존재하지 않을 때 예외처리를 했다면, CBV에서는 def get_object(self, pk)로 처리함