APIView
는 Django의 기본 View
를 확장하여 RESTful API를 쉽게 구축할 수 있도록 해주는 클래스입니다. Django의 View
와 유사하지만, APIView
는 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 명확하게 처리할 수 있는 구조를 제공합니다.
Request
객체를 사용하여, 파싱된 데이터에 쉽게 접근할 수 있습니다.Response
객체를 사용하여, API 응답을 반환합니다.rest_framework.status
모듈을 사용해 HTTP 상태 코드를 명확하게 반환할 수 있습니다.APIView
클래스에 권한, 스로틀링 등의 기능을 쉽게 통합할 수 있습니다.실제 개발에서 많이 사용하진 않음
APIView를 통해 GET POST 요청 처리
# blog/views/api_views.py
class BlogListAPIView(APIView):
def get(self, request, format = None) # format None을 통해 다양한 응답 형식을 지원(JSON, XML, ...)
blog_list = Blog.objects.all().order_by('created_at).select_related('author')
serializer = BlogSerializer(blog_list, manay=True)
return Response(serializer.data)
# blog/urls/api_urls.py
from django.urls import path, include
from blog.views.api_views import BlogListAPIView
app_name ='api'
urlpatterns = [
path('', BlogListAPIView.as_view(),name='blog_list'),
]
def get(self, request, format=None):
blog_list = Blog.objects.all().order_by('created_at').select_related('author')
serializer = BlogSerializer(blog_list, many=True)
paginator = PageNumberPagination()
queryset = paginator.paginate_queryset(blog_list, request)
# 추가
return Response(serializer.data)
# blog/views/api_views.py
class BlogDetailAPIView(APIView):
def get(self, request, format=None, *arsg, **kwargs):
blog_list = Blog.objects.all().select_related('author')
pk = kwargs.get('pk', 0) # 딕셔너리 형태
blog = blog_list.filter(pk = pk).first()
if not blog:
raise Http404
serializer = BlogSerializer(blog, many=False)
return Respone(serializer.data)
# blog/urls/api_urls.py
path('blog/<int:pk>', BlogDetailAPIView.as_view(), name='blog_detail'),
@api_view(['GET']) # 어떤 요청을 받을건지 작성
@schema(AutoSchema())
def detail_view(request, pk):
blog_list = Blog.objects.all().select_related('author')
blog = get_object_or_404(blog_list, pk=pk)
serializer = BlogSerializer(blog, many=False)
return Respone(serializer.data)
# blog/urls/api_urls.py
path('blog/fbv/<int:pk>', BlogDetailAPIView.as_view(), name='blog_detail_fbv'),
class BlogListCreateAPIView(APIView): # 같은 url에 넣어야 하는거니까 같이만듬
def get(self, request, format=None):
blog_list = Blog.objects.all().order_by('created_at').select_related('author')
paginator = PageNumberPagination()
queryset = paginator.paginate_queryset(blog_list, request)
serializer = BlogSerializer(queryset, many=True)
return Response(serializer.data)
def post(self, request):
serializer = BlogSerializer(data=request.data) # form 과 유사한 형태로 사용
if serializer.is_valid():
blog = serializer.save()
# Response : JSON 데이터를 자동으로 직렬화, 클라이언트에게 응답을 반환할 때 사용
return Response(serializer.data, status = status.HTTP_201_CREATED)
return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)
author = UserSerializer(many=False, read_only=True)
if serializer.is_valid(): blog = serializer.save(author=request.user)
IsAuthenticatedOrReadOnly
사용from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
class BlogListCreateAPIView(APIView):
# permission_classes = [IsAuthenticated] # 이렇게 하면 Get 요청시에도 로그인이 안되어있으면 막힘
permission_classes = [IsAuthenticatedOrReadOnly] # 읽기만 가능
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication'
]
}
- PUT : 전체칼럼
- PATCH : 일부컬럼도 수정가능, 물론 전체칼럼도 수정가능
class BlogDetailAPIView(APIView):
def get_object(self, request, *args, **kwargs):
# PATCH, PUT, DELETE 요청을 여러 번 보낼 때, 같은 데이터를 여러 번 불러오지 않기 위해 self.object를 사용
if self.object:
return self.object
blog_list = Blog.objects.all().select_related('author')
pk = kwargs.get('pk', 0)
# blog = blog_list.filter(pk=pk).first()
# if not blog:
# raise Http404
blog = get_object_or_404(blog_list, pk=pk)
self.object = blog
return blog
def get(slef, request, formant=None, *args, **kwargs):
blog = self.get_object(request, *args, **kwargs)
serializer = BlogSerializer(blog, many=False)
return Response(serializer.data)
def patch(self, request, *args, **kwargs):
blog = self.get_object(request, *args, **kwargs)
serializer = BlogSerializer(blog, data=request.data, partial=True) # 일부분 식 하는것을 허용)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, *args, **kwargs):
blog = self.get_object(request, *args, **kwargs)
blog.delete()
return Response({
'deleted': True,
}, status.HTTP_200_OK)
from rest_framework import permissions
class IsAuthorOrReadOnly(permissions.BasePermission):
def has_pers(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
obj = view.get_object(request, *view.args, **view.kwargs)
return obj.author == request.user
permission_classes = [IsAuthorOrReadOnly]
DetailAPIView 에 추가