DRF로 APIView, Json 응답뷰 만들기

2022. 7. 11. 23:02강의 정리/Django REST Framework

반응형

출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard

 

장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생각이 있으신 분은 위 출처의 강의를 적극 추천드립니다!!!

 

 


ModelSerializer를 통한 JSON 직렬화


_Serializer / ModelSerializer은 Form / ModelForm과 유사합니다.

    -> 역할 면에서 Serializer은 POST 요청만 처리하는 Form

 

  • 둘의 공통점
    • 폼 필드 지정 혹은 모델로부터 읽어오기.
    • 입력된 데이터에 대한 유효성 검사를 통해 저장합니다.
  • 둘의 차이점
    • Form / ModelForm : Form태그가 포함된 HTML을 생성합니다.
    • Serializer / ModelSerializer : Form 데이터가 포함된 JSON 문자열을 생성합니다.

 


 

Serializer를 통한 뷰처리(DRF를 사용하지 않을 때)


from rest_framework.serializers import ModelSerializer

# Post모델에 대한 ModelSerializer 정의
class PostSerializer(ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'

# Views
serializer = PostSerializer(data=request.POST)
if serializer.is_valid():
	# 유효성 검사에 통과한 값들을 전달
	return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
  • Form 생성자의 첫번째 인자는 data이지만, Serializer 생성자의 첫번째 인자는 instance이다.

 


 

DRF의 기본 CBV인 APIView


  • APIView 클래스 혹은 @api_view장식자
  • View에 여러 기본 속성을 부여한다.
    1. renderer_classes: 직렬화 class 다수
    2. parser_classes: 비직렬화 class 다수
    3. authentication_classes: 인증 class 다수 -> 유저를 식별하는 것
    4. throttle_classes: 사용량 제한 class 다수(호출 제한)
    5. permission_classes: 권한 class 다수 -> 유저를 식별하고 나서 각 자원에 대해 접근 레벨을 정의
    6. content_negotiation_class: 요청에 따라 적절한 직렬화/비직렬화 class를 선택하는 class
    7. metadata_class: 메타 정보를 처리하는 class
    8. versioning_class: 요청에서 API버전 정보를 감지하는 class
  • 각 옵션의 디폴트 값
    1. renderer_classes
      • rest_framework.renderers.JSONRenderer : JSON 직렬화
      • rest_framework.renderers.TemplateHTMLRenderer : HTML 페이지 직렬화
    2. parser_classes
      • rest_framework.parsers.JSONParser : JSON 포맷 처리
      • rest_framework.parsers.FormParser
      • rest_framework.parsers.MultiPartParser
    3.  authentication_classes
      • rest_framework.authentication.SessionAuthentication : 세션에 기반한 인증
      • rest_framework.authentication.BasicAuthentication : HTTP Basic 인증
    4. throttle_classes
      • 빈 튜플 (디폴트로는 요청 횟수 제한이 설정 되어 있지 않음)
    5. permission_classes
      • rest_framework.permissions.AllowAny : 누구라도 접근 허용
    6. content_negotiation_class
      • rest_framework.negotiation.DefaultContentNegotiation
      • 같은 URL로의 요청이지만, JSON응답을 요구하는 것이냐 / HTML응답을 요구하는 것인지 판단
    7. metadata_class
      • rest_framework.metadata.SimpleMetadata
    8. versioning_class
      • None: API 버전 정보를 탐지하지 않겠다.
      • 요청 URL에서, GET인자에서, HEADER에서 버전 정보를 탐지하여 해당 버전의 API뷰가 호출되도록 합니다.

 


 

APIView와 @api_view


  1. APIView : 클래스 기반 뷰//상속 받아야 함
  2. @api_view : 함수 기반 뷰를 위한 장식자

 


APIView


  • 하나의 CBV 이므로  -> 하나의 URL만 처리 가능
    • 그러나 ApiView를 좀더 표준화-> Generic 
    • Generic을 좀더 합친 것: ViewSet
    • ViewSet은 여러개의 URL의 대응이 가능하다.
    • 즉 ApiView와 Generic은 하나의 get, post, put, delete의 url만 매핑 가능하다면 ViewSet은 두개의 url 매핑 가능
  • 각 method(get, post, put, delete)에 맞게 멤버함수를 구현하면, 해당 method 요청이 들어올 때 호출. 호출 이전 단계(initial)에서 다음을 처리함
    • // APIView를 상속받을 때 자동으로 처리되는 작업들 
    • 직렬화 / 비직렬화 처리(JSON 등)
    • 인증 체크
    • 사용량 제한 체크: 호출 허용량 범위인지 체크
    • 권한 클래스 지정: 비인증/인증 유저에 대해 해당 API 호출을 허용할 것인지를 결정
    • 요청된 API버전 문자열을 탐지하여, request.version에 저장

 

 


 

클래스 형태) APIView 구현 샘플


get, post등을 직접 구현 하였으나 직렬화, 인증 등은 APIView에 포함되어있고, 우리는 그것을 상속 했으므로 직접 구현하지 않아도 된다.

 

 

list / create

from rest_framework.response import Response
from rest_framework.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)

 

 

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)
  • 위 메소드들은 무슨 프로젝트를 진행하더라도 거의 비슷하게 작성되고, 반복된다. 이를 패턴화 한게 generics이고, generics를 합쳐서 구조화 시킨 것을 viewset이라 한다.

 

# 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)
  • 뷰가 csrf_exempt 장식자로 이미 감싸져있기에 POST 요청에서 csrf token 체크를 하지 않습니다.
  • 이를 이해하기 위해서 파이썬 장식자를 공부할 필요가 있다!!!

 

 


 

함수 형태) @api_view 장식자 구현 샘플


  • 하나의 작업만을 구현코자 할 때 @api_view를 쓰면 편리하다.

 

List / create

from django.http import get_object_or_404
from rest_framework import status
from rest_framework.response import 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)
  • 함수형 뷰에서는 각 요청을 if문으로 처리한다.

 

 

detail / update / delete

from rest_framework.decorators import api_view
from rest_framework.response import Response

**@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)

 

 


https://www.django-rest-framework.org/api-guide/fields/

 

Serializer fields - Django REST framework

 

www.django-rest-framework.org

https://velog.io/@kmnkit/drf-rwonly

 

Serializer 필드 작성 방법

Serializer를 쓸 때 헷갈리는 필드 정하는 방법.

velog.io

  • serializer field를 통해 읽기만 해야하는 필드, 쓰기만 해야하는 필드, 둘 다 해야하는 필드로 나눌 수 있다.

 

 

혼자만의 깨달음

왜 DRF의 페이지에서는 해당 페이지로 보내진 API(JSON)만 보이고, 기존 Django에서 보이던 페이지들이 왜 안보이지라고 생각했었는데 정말 무지했다.

DRF의 목적은 프론트단에 API를 보내주는게 목적이거늘 Django처럼 풀스택만을 지원한다고 생각했던 것이 패착이었다.

이 이유로 DRF의 view단에서 return response를 보내줄 때 html을 render하지 않고 data만 보내준다.

 

 

반응형

'강의 정리 > Django REST Framework' 카테고리의 다른 글

DRF ViewSet과 Router  (0) 2022.07.13
DRF mixins 상속을 통한 APIView  (0) 2022.07.12
Django JSON 직렬화  (0) 2022.03.22
Django JSON 응답뷰  (0) 2022.03.12
Django API와 REST  (0) 2022.03.10