파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 강의를 듣고 정리한 글입니다.
Form 처리와 유사한 방식으로 동작
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
# Views
"""주의) Form 생성자의 첫번째 인자는 data이지만,
Serializer 생성자의 첫번째 인자는 instance임. """
serializer = PostSerializer(data=request.POST)
if serializer.is_valid():
return JsonResonse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
@api_view
장식자 View에 여러 기본 속성을 부여한다.rest_framework.renderers.JSONRenderer
: JSON 직렬화rest_framework.renderers.TemplateHTMLRenderer
: HTML 페이지 직렬화rest_framework.parsers.JSONParser
: JSON 포맷 처리rest_framework.parsers.FormParser
rest_framework.parsers.MultiPartParser
rest_framework.authentication.SessionAuthentication
: 세션에 기반한 인증rest_framework.authentication.BasicAuthentication
: HTTP Basic 인증rest_framework.permissions.AllowAny
: 누구라도 접근 허용rest_framework.negotiation.DefaultContentNegotiation
rest_framework.metadata.SimpleMetadata
공식 튜토리얼: https://www.django-rest-framework.org/tutorial/3-class-based-views/
APIView
: 클래스 기반 뷰@api_view
: 함수 기반 뷰를 위한 장식자def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
**[self.initial(request, *args, **kwargs)](https://www.notion.so/EP04-APIView-a08bfeb63a2c49dea8431398488ad049)**
# Get the appropriate handler method
if request.method.lower() in self.http_method_names: # 지원하는 method 목록에 있다면
handler = getattr(self, request.method.lower(), # 해당 멤머함수를 찾는다.
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs) # 지원하는 method 멤버함수 호출
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # 어떤 format 응답?
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request) # content 탐지
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs) # version 탐지
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
self.perform_authentication(request) # 인증
self.check_permissions(request) # permission
self.check_throttles(request) # 요청 수 제한
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)
# 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_exampt 장식자로 이미 감싸져 있기에](https://github.com/encode/django-rest-framework/blob/de497a9bf12605b8b71bf7c21da57bc2a8238786/rest_framework/views.py#L144) POST요청에서 csrf token체크를 하지 않는다.
delete/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)
하나의 작업 만을 구현코자 할 때 @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)
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)