APIView


๐Ÿ’ก Serializer๋ฅผ ํ†ตํ•œ View ์ฒ˜๋ฆฌ

Serializer๋ฅผ ํ†ตํ•œ View ์ฒ˜๋ฆฌ๋Š” Form ์ฒ˜๋ฆฌ์™€ ์œ ์‚ฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'

# views.py ; ์—ฌ๊ธฐ์„œ๋Š” DRF๊ธฐ๋Šฅ์€ ๊ฑฐ์˜ ์—†๋‹ค.
serializer = PostSerialize(data=request.POST)
if serializer.is_valid():
    return JsonReponse(seializer.data, status=200)
return JsonResponse(serializer.errors, status=400)

์—ฌ๊ธฐ์„œ ๋‘˜์˜ ์ฐจ์ด์ ์€ Form ์ƒ์„ฑ์ž์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” data์ด์ง€๋งŒ,

Serializer ์ƒ์„ฑ์ž์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” instance์ด๋‹ค.

instance ์ธ์ž์—๋Š” โ€˜๋ชจ๋ธ ๊ฐ์ฒดโ€™ ํ˜น์€ โ€˜Querysetโ€™์„ ์ „๋‹ฌํ•ด์ค€๋‹ค.

# django/forms/forms.py/BaseForm
class BaseForm(RenderableFormMixin):
    # ์ƒ๋žต
    def __init__(self,data=None,):
        # ์ƒ๋žต

# rest_framework/serializers.py/BaseSerializer
class BaseSerializer(Field):
    def __init__(self, instance=None, data=empty, **kwargs):
        # ์ƒ๋žต


๐Ÿ’ก DRF์˜ ๊ธฐ๋ณธ CBV์ธ APIView

DRF๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด โ€œAPIView ํด๋ž˜์Šคโ€๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ View๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

์‹ค์ œ๋กœ GenericAPIView๋Š” APIView๋ฅผ ์ƒ์† ๋ฐ›๊ณ , queryset๊ณผ serializer_class์„

์ œ์™ธํ•˜๊ณ ๋Š” default๊ฐ’์„ ์‚ฌ์šฉํ•œ๋‹ค.

# rest_framework/generics.py
class GenericAPIView(views.APIView):
    queryset = None
    serializer_class = None
    # ์ƒ๋žต


๋˜ํ•œ ํ•จ์ˆ˜ ๊ธฐ๋ฐ˜ View๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด, @api_view๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

# rest_framework/decorators.py/
def api_view(http_method_names=None):
    """
    FBV๋ฅผ APIView ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ.
    View์— ๋Œ€ํ•ด ํ—ˆ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ ๋ชฉ๋ก์„ ์ธ์ˆ˜๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
    """
    http_method_names = ['GET'] if (http_method_names is None) else http_method_names

    def decorator(func):

        WrappedAPIView = type(
            'WrappedAPIView',
            (APIView,),
            {'__doc__': func.__doc__}
        )

Python์˜ type์„ ํ™œ์šฉํ•˜์—ฌ ๋™์ ์œผ๋กœ APIView ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์€

WrappedAPIView ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๋‹ค.

์ฆ‰, @api_view๋„ APIViewํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.


APIView ํด๋ž˜์Šค๋Š” View์— ์—ฌ๋Ÿฌ ๊ธฐ๋ณธ ์†์„ฑ์„ ๋ถ€์—ฌํ•œ๋‹ค.

์•„๋ž˜์˜ ํด๋ž˜์Šค๋Š” ๋ชจ๋‘ ์‚ฌ์šฉ์ž๊ฐ€ ์ปค์Šคํ…€ ๊ฐ€๋Šฅํ•˜๋‹ค.


  1. renderer_classes : ์ง๋ ฌํ™” class
    • rest_framework.renderers.JSONRenderer : JSON ์ง๋ ฌํ™”
    • rest_framework.renderers.TemplateHTMLRendere` : HTML ํŽ˜์ด์ง€ ์ง๋ ฌํ™”
  2. parser_classes : ๋น„์ง๋ ฌํ™” class
    • rest_framework.parsers.JSONParser : JSON ํฌ๋งท ์ฒ˜๋ฆฌ
    • rest_framework.parsers.FormParser
    • rest_framework.parsers.MultiPartParser
  3. authentication_classes : ์ธ์ฆ class
    • user๋ฅผ ์‹๋ณ„ํ•œ๋‹ค.
    • rest_framework.authentication.SessionAuthentication : ์„ธ์…˜์— ๊ธฐ๋ฐ˜ํ•œ ์ธ์ฆ
    • rest_framework.authentication.BasicAuthentication : HTTP Basic ์ธ์ฆ
  4. throttle_classes : ์‚ฌ์šฉ๋Ÿ‰ ์ œํ•œ class
    • ๋นˆ ํŠœํ”Œ
  5. permission_classes : ๊ถŒํ•œ class
    • user๋ฅผ ์‹๋ณ„ ํ›„ ๊ฐ๊ฐ์˜ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•ด์„œ ์ ‘๊ทผ ๊ถŒํ•œ ํ™•์ธ
    • 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 vs @api_view

DRF์˜ 2๊ฐ€์ง€ ๊ธฐ๋ณธ View๊ฐ€ ์žˆ๋Š”๋ฐ, APIView(โ†” View)์™€

@api_view(โ†” request)๊ฐ€ ์žˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ APIView ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์•ผ๋งŒ

์•ž์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ธฐ๋Šฅ๋“ค์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.


๐Ÿ”Ž APIView

APIView๋Š” ํ•˜๋‚˜์˜ CBV๋กœ ํ•˜๋‚˜์˜ URL๋งŒ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด๊ฒƒ์„ ์กฐ๊ธˆ ํ‘œ์ค€ํ™”ํ•ด ๋†“์€ ๊ฒƒ์ด Generic์ธ๋ฐ, Generic๋„ APIView์™€

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•˜๋‚˜์˜ URL๋งŒ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

๋ฐ˜๋ฉด์—, ViewSet์€ 2๊ฐœ์˜ URL์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋Š” Generic์„ ๊ตฌ์ฒดํ™” ํ•œ ํด๋ž˜์Šค์ด๋‹ค.


์•„๋ž˜๋Š” APIView์˜ ์ดˆ๊ธฐํ™”(Initial) ์„ค์ • ๋‹จ๊ณ„์ธ๋ฐ

1. ์ง๋ ฌํ™”/๋น„์ง๋ ฌํ™” ์ฒ˜๋ฆฌ (JSON ๋“ฑ)

2. ์ธ์ฆ ์ฒดํฌ

3. ์‚ฌ์šฉ๋Ÿ‰ ์ œํ•œ ์ฒดํฌ : ํ˜ธ์ถœ ํ—ˆ์šฉ๋Ÿ‰ ๋ฒ”์œ„์ธ์ง€ ์ฒดํฌ

4. ๊ถŒํ•œ ํด๋ž˜์Šค ์ง€์ • : ๋น„์ธ์ฆ/์ธ์ฆ ์œ ์ €์— ๋Œ€ํ•ด ํ•ด๋‹น API ํ˜ธ์ถœ์„ ํ—ˆ์šฉํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒฐ์ •

5. ์š”์ฒญ๋œ API ๋ฒ„์ „ ๋ฌธ์ž์—ด์„ ํƒ์ง€ํ•˜์—ฌ, request.version์— ์ €์žฅ

์ดˆ๊ธฐํ™” ๋‹จ๊ณ„์—์„œ ํ•„์š”ํ•œ ๊ฒƒ๋“ค์„ ๋ชจ๋‘ ์„ค์ •ํ•œ ์ดํ›„์—,

๊ฐ method(get, post, put, delete)๋ฅผ ํ˜ธ์ถœํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ์ด APIView์— ์žˆ๋‹ค.

# rest_framework/views.py

def dispatch(self, request, *args, **kwargs):
    # ์ƒ๋žต
    try:
        self.initial(request, *args, **kwargs)

        if request.method.lower() in self.http_method_names: # ์ง€์›ํ•˜๋Š” Http ๋ฉ”์†Œ๋“œ
            handler = getattr(self, request.method.lower(),
                                self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed

        response = handler(request, *args, **kwargs)

    except Exception as exc:
        response = self.handle_exception(exc)

    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

# def initial

def initial(self, request, *args, **kwargs):

    self.format_kwarg = self.get_format_suffix(**kwargs)

    neg = self.perform_content_negotiation(request)
    request.accepted_renderer, request.accepted_media_type = neg

    version, scheme = self.determine_version(request, *args, **kwargs)
    request.version, request.versioning_scheme = version, scheme

    self.perform_authentication(request)
    self.check_permissions(request)
    self.check_throttles(request)


ํด๋ž˜์Šค ํ˜•ํƒœ์˜ 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.user)
        if serializer.is_valid():
            return Response(serializer.data, status=201)
        return Response(serializer.data, 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)

APIView ํด๋ž˜์Šค์—์„œ View๊ฐ€ ์ด๋ฏธ csrf_exempt๋กœ ์ด๋ฏธ ๊ฐ์‹ธ์ ธ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ POST ์š”์ฒญ์—์„œ csrf token ์ฒดํฌ๋ฅผ ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.



ํด๋ž˜์Šค ํ˜•ํƒœ์˜ 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 ๊ตฌํ˜„์—์„œ ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋“ค์ด ๋ณด์ธ๋‹ค.

์ด๋ ‡๊ฒŒ ๋ฐ˜๋ณต๋˜๋Š” ๋ถ€๋ถ„์„ ํŒจํ„ดํ™” ์‹œ์ผœ๋†“์€ ๊ฒƒ์ด Genrics๋‹ค



@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 ์˜†์— ์–ด๋–ค method๋ฅผ ์ง€์›ํ•  ๊ฒƒ์ธ์ง€

๋ฆฌ์ŠคํŠธ๋กœ ๊ผญ ์ž…๋ ฅ์„ ํ•ด์ค˜์•ผํ•œ๋‹ค.

ํ•ด๋‹น method๊ฐ€ ์š”์ฒญ์ด ๋์„ ๋•Œ 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 = PostSerilizer(post, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Responser(serializer.data)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

    else:
        post.delet()
    
    return Response(status=status.HTTP_204_NO_CONTENT)


์œ„ ์ฝ”๋“œ๋“ค์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด CBV ๋˜๋Š” FBV ๋ชจ๋‘ ๊ฐ™์€ ์˜๋ฏธ์˜ ์ฝ”๋“œ๋ฅผ

๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ƒํ™ฉ์— ๋งž์ถฐ์„œ ์ ์ ˆํ•œ ์„ ํƒ์„ ํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.