[Django Rest Framework] API View

Serializer를 통한 뷰 처리

Donnis Dev-note
9 min readMar 12, 2020

Serializer는 Form 처리와 유사한 방식으로 동작합니다.

# Form 생성자의 첫 인자는 data 지만 Serializer의 첫 인자는 instance
# 두 번째 인자가 data
serializer = PostSerializer(data = request.POST)if serializer.is_valid():
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)

DRF의 기본 CBV, APIView

APIView 클래스 or @api_view 장식자
View에 여러 기본 속성을 부여 (각각의 디폴트값 정리)

  1. renderer_classes :직렬화 class
    - JSONRenderer, TemplateHTMLRenderer
  2. parser_classes :비직렬화 class
    - JSONParser, FormParser, MultiPartParser
  3. authentication_classes :인증 class
    - SessionAuthentication(세션 기반), BasicAuthentication(HTTP Basic)
  4. throttle_classes : 사용량 제한 class
    - 빈 튜플
  5. permission_classes : 권한 class
    - AllowAny : 누구라도 접근 허용
  6. content_negotiation_class : 요청에 따라 적절한 직렬화/비직렬화 class를 선택하는 class
    - DefaultContentNegotiation
    -같은 URL 요청이지만, JSON응답 요구인지 HTML 응답 요구인지 판단
  7. metadata_class : 메타 정보 처리 class
    SimpleMetadata
  8. versioning_class : 요청에서 API버전 정보를 탐지하는 class
    - None : API 버전 정보 탐지 X
    - 요청 url, GET인자, Header에서 버전정보 탐지, 해당 버전 API뷰 호출되도록 함.

-APIView에서 사용할 수 있는 기능들이라고 볼 수 있습니다.-

APIView : 클래스 기반 뷰

하나의 CBV 이므로 하나의 URL만 처리가능합니다.
(APIView를 표준화 시킨 것은 Generic, Generic을 표준화한 것이 ViewSet)
(APIView와 Generic은 하나의 클래스가 하나의 url을 처리하지만, ViewSet은 2개의 url도 하나의 클래스에서 처리가 가능합니다.)

APIView 내의 self.Initial에서의 세팅 5가지

- 직렬화 / 비직렬화 처리 (JSON 등)

- 인증 체크

- 사용량 제한 체크 : 호출 허용량 범위인지

- 권한 클래스 지정 : 비인증/인증 유저에 대해 해당 API호출 허용 여부 결정

- 요청된 API 버전 문자열 탐지, request.version에 저장

위의 세팅을 다 거친 다음에 각 method(get, post, put, delete)에 맞게 멤버함수를 구현하면, 해당 method 요청이 들어올 때 호출

(APIView 내부의 dispatch에서 인증, 권한, 사용량 제한, negotiation 확인)

# APIView 구현 Sample 예제# 위의 5가지 세팅은 APIView 내부에서 알아서 진행되고, 그 뒤에 get,post..
# 등 method를 처리하는 것임!
# 상속받은 APIView 내부에서 return csrf_exempt(view) 형태로 감싸져
# 있기 때문에 post 요청에서 csrf_token 체크를 하지 않음!
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)
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)
# 이렇게 list, detail에서의 5가지 메소드를 패턴화시킨 것이 generics
# ex) generics.ListAPIView, .CreateAPIView, .DestroyAPIView....
# generics를 합쳐서 구조화 시켜놓은 것이 ViewSet

@api_view : 함수 기반 뷰 장식자

# 함수 형태 @api_view 장식자 구현 Sample 예제

@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(['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)

클래스나 함수 중에 뭐가 더 낫다 할 수는 없으며, 비교해서 사용하면 됩니다.

generics 기반 뷰

class PublicPostListAPIView(generics.ListAPIView):
queryset = Post.objects.filter(is_public=True)
serializer_class = PostSerializer

APIView 상속, 클래스 뷰

  • (Class Based View)APIView 상속받아 위의 generics와 똑같이 구현
class PublicPostListAPIView(APIView):
def get(self, request):
qs = Post.objects.filter(is_public=True)
serializer = PostSerializer(qs, many=True)
return Response(serializer.data)
public_post_list = PublicPostListAPIView.as_view()

@api_view장식자 사용, 함수 뷰

@api_view(['GET'])
def public_post_list(request):
qs = Post.objects.filter(is_public=True)
serializer = PostSerializer(qs, many=True)
return Response(serializer.data)

--

--