Django DRF APIView for CRUD

Haks.·2025년 2월 7일
0

How to use

목록 보기
20/32

Tip

  • shift + F6 bloglist -> 수정시 전체 파일 해당 이름 수정

APIView

APIView는 Django의 기본 View를 확장하여 RESTful API를 쉽게 구축할 수 있도록 해주는 클래스입니다. Django의 View와 유사하지만, APIView는 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 명확하게 처리할 수 있는 구조를 제공합니다.

주요 특징

  • Request 객체: Django의 HttpRequest를 확장한 Request 객체를 사용하여, 파싱된 데이터에 쉽게 접근할 수 있습니다.
  • Response 객체: Django의 HttpResponse를 확장한 Response 객체를 사용하여, API 응답을 반환합니다.
  • Status 코드: rest_framework.status 모듈을 사용해 HTTP 상태 코드를 명확하게 반환할 수 있습니다.
  • Permissions, Throttling: APIView 클래스에 권한, 스로틀링 등의 기능을 쉽게 통합할 수 있습니다.

APIView의 장점

  • 세밀한 제어: 각 HTTP 메서드에 대한 동작을 세밀하게 제어할 수 있습니다.
  • 명확한 구조: RESTful API의 각 엔드포인트에 대해 명확한 코드 구조를 유지할 수 있습니다.

DRF APIView를 통해 CRUD 제작

실제 개발에서 많이 사용하진 않음

📝 ListView

APIView를 통해 GET POST 요청 처리

  1. api_views.py
# 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'),
]
  1. POSTMAN GET 요청 해당 도메인으로 전송
  2. 페이지 네이션
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)

📝 DetailView

# 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'),

📝 CREATE List와 함께 제작

  1. BlogList => BlogListCreateAPIView
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)
  1. POSTMAN 으로 데이터 전송시 author 가 없어 안됨 , 기존의 form 의 사용법과 다르게 serializer에 추가
    author = UserSerializer(many=False, read_only=True)
  2. 그 후 valid 부분에 추가
    if serializer.is_valid(): blog = serializer.save(author=request.user)
  3. 로그인이 안돼어있어 또 POST 불가 로그인 기능 처리
  4. 기존의 LoginRequiredMixin 기능을 사용할 수 없어 IsAuthenticatedOrReadOnly 사용
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
class BlogListCreateAPIView(APIView):
    # permission_classes = [IsAuthenticated] # 이렇게 하면 Get 요청시에도 로그인이 안되어있으면 막힘
    permission_classes = [IsAuthenticatedOrReadOnly] # 읽기만 가능
  1. restframework에서 POST 요청을 POSTMAN에서 넣는 방법 로그인 안하고, settings.py REST_FRAMEWORK 에 기능 추가
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication'
    ]
}
  1. POSTMAN Auth 에서 BasicAuth 선택후 아이디 넣고 POST 요청시 잘만들어짐

📝 UPDATE, DELETE

  • 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)
  1. 로그인 처리를 해주어야 하는데 로그인도 되어있어야 하고 같은 유저여야 한다.
  2. permission을 해주는 함수 제작 utils/permissions.py 제작
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
  1. permission_classes = [IsAuthorOrReadOnly] DetailAPIView 에 추가
  2. 포스트맨으로 patch 실행시 동작 (Auth는 로그인 되어있어야함)

0개의 댓글

관련 채용 정보