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์ ์ฌ๋ฌ ๊ธฐ๋ณธ ์์ฑ์ ๋ถ์ฌํ๋ค.
์๋์ ํด๋์ค๋ ๋ชจ๋ ์ฌ์ฉ์๊ฐ ์ปค์คํ ๊ฐ๋ฅํ๋ค.
- renderer_classes : ์ง๋ ฌํ class
- rest_framework.renderers.JSONRenderer : JSON ์ง๋ ฌํ
- rest_framework.renderers.TemplateHTMLRendere` : HTML ํ์ด์ง ์ง๋ ฌํ
- parser_classes : ๋น์ง๋ ฌํ class
- rest_framework.parsers.JSONParser : JSON ํฌ๋งท ์ฒ๋ฆฌ
- rest_framework.parsers.FormParser
- rest_framework.parsers.MultiPartParser
- authentication_classes : ์ธ์ฆ class
- user๋ฅผ ์๋ณํ๋ค.
- rest_framework.authentication.SessionAuthentication : ์ธ์ ์ ๊ธฐ๋ฐํ ์ธ์ฆ
- rest_framework.authentication.BasicAuthentication : HTTP Basic ์ธ์ฆ
- throttle_classes : ์ฌ์ฉ๋ ์ ํ class
- ๋น ํํ
- permission_classes : ๊ถํ class
- user๋ฅผ ์๋ณ ํ ๊ฐ๊ฐ์ ๋ฆฌ์์ค์ ๋ํด์ ์ ๊ทผ ๊ถํ ํ์ธ
- rest_framework.permissions.AllowAny : ๋๊ตฌ๋ผ๋ ์ ๊ทผ ํ์ฉ
- content_negotiation_class : ์์ฒญ์ ๋ฐ๋ผ ์ ์ ํ ์ง๋ ฌํ/๋น์ง๋ ฌํ class๋ฅผ ์ ํํ๋ class
- rest_framework.negotiation.DefaultContentNegotiation
- ๊ฐ์ URL๋ก์ ์์ฒญ์ด์ง๋ง, JSON์๋ต์ ์๊ตฌํ๋ ๊ฒ์ด๋ / HTML์๋ต์ ์๊ตฌํ๋ ๊ฒ์ธ์ง ํ๋จ
- metadata_class : ๋ฉํ ์ ๋ณด๋ฅผ ์ฒ๋ฆฌํ๋ class
- rest_framework.metadata.SimpleMetadata
- 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 ๋ชจ๋ ๊ฐ์ ์๋ฏธ์ ์ฝ๋๋ฅผ
๊ตฌํํ ์ ์๋ค. ์ํฉ์ ๋ง์ถฐ์ ์ ์ ํ ์ ํ์ ํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.