DRF의 2가지 기본 뷰
APIView : 클래스 기반 뷰
@api_view : 함수 기반 뷰를 위한 장식자
두 가지 다 View에 여러 기본 속성 부여
1. renderer_classes : 직렬화 class 다수
- rest_framework.renderers.JSONRenderer : JSON직렬화
- rest_framework.renderers.TemplateHTMLRenderer : HTML 페이지 직렬화
2. parser_classes : 비 직렬화 class 다수
- rest_framework.parsers.JSONParser : JSON 포맷 처리
- rest_framework.parsers.FormParser
- rest_framework.parsers.MultiPartParser
3. authentication_classes : 인증 class 다수
- rest_framework.authentication.SessionAuthentication : 세션에 기반한 인증
- rest_framework.authentication.BasicAuthentication : HTTP Basic 인증
4. throttle_classes : 사용량 제한 class 다수
- 빈 튜플
5. permission_classes : 권한 class 다수
- rest_framework.permissions.AllowAny : 누구라도 접근 허용
6. content_negotiation_class : 요청에 따라 적절한 직렬화/비 직렬화 class를 선택하는 class
- rest_framework.negotiation.DefaultContentNegotiation : 같은 URL로의 요청이지만, JSON 응답을 요구하는 것인지 / HTML 응답을 요구하는 것인지 판단
7. metadata_class : 메타 정보를 처리하는 class
- rest_framework.metadata.SimpleMetadata
8. versioning_class : 요청에서 API버전 정보를 탐지하는 class
- None : API 버전 정보를 탐지하지 않겠다
- 요청 URL에서, GET인자에서, HEADER에서 버전정보를 탐지하여 해당 버전의 API뷰가 호출되도록 한다
APIView
하나의 CBV 이므로 하나의 URL만 처리 가능
1. initial (초기화) 단계
- 직렬화/비직렬화 처리 (JSON 등)
- 인증 체크
- 사용량 제한 체크 : 호출 허용량 범위인지 체크
- 권한 클래스 지정 : 비인증/인증 유저에 대해 해당 API 호출을 허용할 것인지를 결정
- 요청된 API 버전 문자열을 탐지하여, request.version에 저장
2. 요청이 들어올 때 미리 구현해둔 method(get, post, put, delete)에 맞게 멤버 함수를 호출
APIView 구현 예시
(1) 클래스 형태
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from .models import Post
from .serializers import PostSerializer
class PostListAPIView(APIView):
def get(self, request):
qs = Post.obejcts.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 )
class PostDetailAPIView(APIView):
def get(self, request, pk, format=None):
post = get_object_or_404(Post, pk=pk)
serializer = PostSerializer(post)
return Response(serializer.data)
def put(self, request, pk):
post = get_object_or_404(Post, pk=pk)
# Form 생성자의 첫번째 인자는 data이지만, Serializer 생성자의 첫번째 인자는 instance이다
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 = get_object_or_404(Post, pk=pk)
post.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
(2) 함수 형태
from django.shortcuts import get_object_or_404
from rest_framework import Response, status
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':
qs = Post.objects.all()
serializer = PostSerializer(qs, 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.error, status=400)
@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':
# Form 생성자의 첫번째 인자는 data이지만, Serializer 생성자의 첫번째 인자는 instance이다
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)
※ 하나의 작업만을 구현하고자 한다면 @api_view를 쓰는 것이 더 편리!
class PublicPostListAPIView(APIView):
def get(self, request):
qs = Post.objects.filter(is_public=True)
serializer = PostSerializer(qs, many=True)
return Response(serializer.data)
@api_view(['GET'])
def public_post_list(request):
qs = Post.objects.filter(is_public=True)
serializer = PostSerializer(qs, many=True)
return Response(serializer.data)
c.f) 위와 같은 코드를 generics를 이용해서 구현해볼 수도 있다
class PublicPostListAPIView(generics.ListAPIView):
queryset = Post.objects.filter(is_public=True)
serializer_class = PostSerializer
APIView를 좀 더 표준화한 것이 Generic 이고 이것을 좀 더 표준화 한 것이 ViewSet이다
- APIView와 Generic : 하나의 클래스가 하나의 URL에 매핑
- ViewSet : 하나의 클래스가 두 개의 URL에 대한 처리