APIView와 @api_view

최동혁·2022년 12월 6일
0

DRF

목록 보기
5/19

APIView와 @api_view

DRF의 2가지 기본 뷰

  1. APIView : 클래스 기반 뷰
  2. @api_view : 함수 기반 뷰를 위한 장식자

APIView

APIView를 조금 더 표준화 시킨것이 Generic

Generic을 합쳐 놓은 것이 Viewset이다.

  • APIView와 Generic 까지는 하나의 클래스는 하나의 URL로만 매핑된다.
  • Viewset은 두개의 URL에 대한 처리를 하나의 클래스에서 처리해준다.
  • 예를 들면 Generic까지는 포스트의 수정, 삭제, 생성 등 중에 1개만 구현
  • Viewset은 다수를 엮어서 구현

하나의 CBV이므로 -> 하나의 URL만 처리 가능

각 method(get, post, put, delete)에 맞게 멤버함수를 구현하면, 해당 method 요청이 들어올 때 호출

  1. 직렬화/비직렬화 처리 (JSON 등)
  2. 인증 체크
  3. 사용자 제한 체크 : 호출 허용량 범위인지 체크
  4. 권한 클래스 지정 : 비인증/인증 유저에 대해 해당 API 호출을 허용할 것인지를 결정
  5. 요청된 API 버전 문자열을 탐지하여, request.version에 저장

APIView 내 dispatch

  • dispatch 함수에서 initial 함수가 있다.
  • 들어가서 보면 포멧, 컨텐트 탐지, 버전 탐지
  • 그리고 마지막에 인증 수행, 퍼미션 체크, 요청 수 제한을 체크한다.
  • 다 이루어지고 난다면 다시 dispatch 함수에서 initial 밑 부분으로 와서 request.method를 보는데 mothod는 전부 대문자이다 (예 : POST, GET, DELETE, PUT)
  • 그렇기 때문에 소문자로 바꾸어 주고, 현재 해당 멤버 함수를 제공해주면 그 멤버함수를 찾아서 호출해준다. (handler가 호출 해주는 함수이다)
  • 그리고 return 값으로 응답을 받고, 리턴해준다.

클래스 형태) APIView 구현 샘플 (list/create)

from rest_framework.response import Response
from rest_fraework.views import APIView
from .models import Post
from .serializers import PostSerializer

class PostListAPIView(APIView):
		def get(self, request):
				qs = Post.objects.all()
				serializer = PostSerializer(qs, many=True)
				return Response(serializer.data)

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

# rest_framework/views.py
from django.views.decorators.csrf import csrf_exempt

class APIView(View):
		# …
		@classmethod
		def as_view(cls, **initkwargs):
				# …
				return csrf_exempt(view)
  • view가 csrf_exempt 장식자로 이미 감싸져 있기에 POST 요청에서 csrf token 체크를 하지 않는다.
@csrf_exempt
def post_list(request):
	pass
def post_list(request):
	pass

post_list = csrf_exempt(post_list)
  • 위의 두 코드는 같은 코드이다.
  • 이것이 파이썬의 장식자 문법이다.
  • 그래서 가장 위의 코드 return csrf_exepmt(view)는 as_view 함수를 호출 했을 때 csrf_exempt(view) 장식자가 씌워져서 나오는 것이다.

클래스 형태) APIView 구현 샘플 (detail/update/delete)

from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Post
from .serializers import PostSerializer

class PostDetailAPIView(APIView):
		def get_object(self, pk):
				return get_object_or_404(Post, pk=pk)

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

		def put(self, request, pk):
				post = self.get_object(pk)
				serializer = PostSerializer(post, 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):
				post = self.get_object(pk)
				post.delete()
				return Response(status=status.HTTP_204_NO_CONTENT)

직접 구현을 했지만..

  • 우리는 APIView 내의 dispatch 함수에서 initial 함수가 하는 역할인 인증, 퍼미션, 요청 수 제한 등 아무것도 하지 않고, 데이터를 받아서 db에 저장해주거나, db에 있는 것들을 가져와서 응답해주기, 상황에 맞는 응답 코드 반응해주기 밖에 하지 않았다.
  • 그래서 이러한 것들을 구현하다 보면 공통되는 패턴이 보인다.
  • 이러한 패턴들을 모아 구현이 되어 있는 것이 drf의 generics이다.

generics의 함수

generics.ListAPIView

generics.CreateAPIView

generics.ListCreateAPIView

  • ListAPIView와 CreateAPIView를 합친 것이 LISTCreateAPIView이다.

generics.DestroyAPIView

generics.UpdateAPIView

  • 등등 엄청나게 많다.
  • 여튼 위에서 직접 구현한 총 5개의 함수들을 패턴화 시켜 놓은 것이 drf의 generics이다.
  • 그리고 이러한 generics를 합쳐서 구조화 시켜 놓은 것이 Viewset이다.

함수 형태) @api_view 장식자 구현 샘플 (list/create)

from django.http import get_object_or_404
from rest_framework import status, Response
from rest_framework.decorators import api_view
from .models import Post
from .serializers import PostSerializer

@api_view(['GET', 'POST'])
def post_list(request):

		if request.method == 'GET':
				serializer = PostSerializer(Post.objects.all(), many=True)
				return Response(serializer.data)
		
		else:
				serializer = PostSerializer(data=request.data)
				if serializer.is_valid():
						serializer.save()
						return Response(serializer.data, status=201)
				return Response(serializer.errors, status=400)
  • 하나의 작업 만을 구현코자 할 때 @api_view를 쓰면 편하다.
  • CBV에서는 def get, def post 이런식으로 구현하면 되는데, FBV에서는 어떤 메소드를 지원하겠다고 list로 꼭 써서 데코레이터로 씌워야한다.
  • 그래서 특정 메소드가 왔을 때, post_list라는 함수가 호출이 되고, if 조건으로 메소드를 통해서 분기처리를 해야 한다.

함수 형태) @api_view 장식자 구현 샘플 (detail/update/delete)

from rest_framework.decorators import api_view

@api_view(['GET', 'PUT', 'DELETE'])
def post_detail(request, pk):
		post = get_object_or_404(Post, pk=pk)

		if request.method == 'GET':
				serializer = PostSerializer(post)
				return Response(serializer.data)

		elif request.method == 'PUT':
				serializer = PostSerializer(post, data=request.data)
				if serializer.is_valid():
						serializer.save()
						return Response(serializer.data)
				return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

		else:
				post.delete()

		return Response(status=status.HTTP_204_NO_CONTENT)
profile
항상 성장하는 개발자 최동혁입니다.

0개의 댓글