[D.R.F] Class based View로 게시글 C.R.U.D API 구현하기

2021. 11. 12. 16:46코딩일지/DRF

Django Class based Views(CBV)는?

FBV가 아닌 CBV를 통해서 로직을 구성하는 것은 다음과 같은 점이 장점이다. 

 1. HTTP 메소드에 따른 처리 코드 작성 시, 기존 FBV에서 사용하던 if 분기 대신 method명으로 깔끔한 로직이 가능

 2. 다중 상속 같은 객체지향 기법을 활용해 Generic, Mixin 클래스 등을 통해 코드의 재사용을 간소화 하고 개발 생산성 증대시킨다.

 

Function based view(FBV)에서 사용한 models.py와 serializers.py를 그대로 사용하겠습니다.

 

1. Views.py 작성

게시글 생성과 목록 불러오기, 게시글 불러오기 삭제, 수정과 댓글을 class별로 나누어 줍니다.

 

  • views.py
    같은 방법으로 import Board, Comment
    from .serializers import BoardSerializers, CommentSerializers, BoardDetailSerializers
    
    from rest_framework.views    import APIView
    from rest_framework.response import Response
    
    
    # 게시글의 목록과 생성
    class BoardListAPIView(APIView):
        def get(self, request):
    # 게시글 목록 불러오기
            boards = Board.objects.all()
            serializer = BoardSerializers(boards, many = True) # Many = True 해줘야 여러 객체들을 불러올 수 있습니다.
            return Response(serializer.data, status = status.HTTP_200_OK)
    
    # 게시글 생성하기
        def post(self, request):
            serializer = BoardSerializers(data = request.data)
            if serializer.is_valid(): # 유효성 검사 True/False값으로 결과값을 지정해줄 수 있다.
                serializer.save() # 저장
                return Response(serializer.data, status = status.HTTP_201_CREATED)
            return Response(status = status.HTTP_400_BAD_REQUEST)
    
    # 게시글불러오기와 수정, 삭제
    class BoardDetailAPIView(APIView):
    # 게시글 불러오기
        def get(self, request, pk):
            # 사용자가 요청한 path Parameter에 넣은 게시글의 pk값 불러오는 게시글의 pk와 일치하는지 검증
            board = Board.objects.get(pk = pk) 
            if board == None:
                return Response(status = status.HTTP_404_NOT_FOUND)
            serializer = BoardDetailSerializers(board)  # 여기선 하나를 가져오기 때문에 Many(x)
            return Response(serializer.data, status = status.HTTP_200_OK)
    
    # 게시글 삭제하기
        def delete(self, pk):
            board = Board.objects.get(pk = pk)
            if board == None:
                return Response(status = status.HTTP_404_NOT_FOUND)
            board.delete()
            return Response(status = status.HTTP_200_OK)
    
    # 게시글 수정하기
        def put(self, request, pk):
            board = Board.objects.get(pk = pk)
            if board == None:
                return Response(status = status.HTTP_404_NOT_FOUND)
            # 수정하기위한 보드 데이터를 불러와 client 요청에 따른 data를 담아주기, 부분적인 수정을 위해 patial = True를 해주어야함
            serializer = BoardSerializers(board, data = request.data, patial = True) 
            if serializer.is_valid(): # 수정 또한 유효성 검사가 필요
                serializer.save()
                return Response(serializer.date, status = status.HTTP_201_CREATED)
            return Response(status = status.HTTP_400_BAD_REQUEST)
    
    # 게시글에 댓글달기
    class CommentCreateAPIView(APIView):
    # 게시글 댓글추가
        def post(self, request, pk, comment_pk):
            board = Board.objects.get(pk = pk) # 클라이언트가 요청하는 게시글
            if board == None:
                return Response(status = status.HTTP_404_NOT_FOUND)
            # ForeignKey로 연결되있는 게시글의 아이디를 같이 요청해야지 client가 요청한 게시글에 댓글을 추가하기위한 로직
            request.data['board'] = board.id 
            serializer = CommentSerializers(data = request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status = status.HTTP_200_OK)
            return Response(status = status.HTTP_400_BAD_REQUEST)
    
    # 댓글 수정,삭제
    class CommentUpdateDeleteAPIView(APIView):
    #여기서 pk는 게시글의 pk, urls.py에서 필요로 하기에 view에서 사용은 안하지만 선언은 해준다.
    #게시글 댓글 삭제
        def delete(self, request, pk, comment_pk):
            #내가 수정하고자 요청한 댓글의 pk와 get으로 가져오는 pk
            comment = Comment.objects.get(pk = comment_pk) 
            if comment == None:
                return Response(status = status.HTTP_404_NOT_FOUND)
            comment.delete()
            return Response(status = status.HTTP_200_OK)
    
    #게시글 댓글 수정
        def put(self, request, pk, comment_pk):
            comment = Comment.objects.get(pk = comment_pk)
            if comment == None:
                return Response(status = status.HTTP_404_NOT_FOUND)
            #게시글 수정과 같은방법으로 진행해준다.
            serializer = CommentSerializers(comment, data = request.data, partial = True)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status = status.HTTP_200_OK)
            return Response(status = status.HTTP_400_BAD_REQUEST)​

2.  URL 지정

FBV처럼 각 클래스의 엔드포인트 url을 지정해줍니다.

 

여기서 as_view()가 붙는데 as_view()는 클래스의 인스턴스를 생성 후, 인스턴스의 dispatch()를 호출한다.

 

dispatch()는 GET, POST 등 HTTP method를 구분하여 해당 인스턴스 내의 get, post 등 메서드로 중계를 한다.

 

만약 해당 메서드가 구현되지 않았을 경우 HttpResponseNotAllowed 예외 발생

 

  • boards/urls.py
    from django.urls import path
    
    from .views import BoardDetailAPIView, BoardListAPIView, CommentCreateAPIView, CommentUpdateDeleteAPIView
    
    
    app_name = 'boards'
    
    urlpatterns = [
        path('', BoardListAPIView.as_view()),
        path('<int:pk>/', BoardDetailAPIView.as_view()),
        path('<int:pk>/comments/', CommentCreateAPIView.as_view()),
        path('<int:pk>/comments/<int:comment_pk>', CommentUpdateDeleteAPIView.as_view())
    ]

 

 3. 서버 가동

  • 서버 실행
    python manage.py runserver​

 

4. 기능 확인

저번 포스팅에서 게시글 생성과 불러오기를 보여드렸으니, 댓글 불러오기와 삭제를 해보겠습니다.

 

게시글 3번에 연결되어있는 댓글 2개

 



3번 게시글에 연결된 댓글 4번, 5번 삭제하기

 

 

삭제 후 3번 게시글을 부르면 빈 리스트가 반환됩니다.

 

 

이번엔 class를 기반으로 한 CBV C.R.U.D를 작성해보았습니다.

 

보시다시피 FBV와는 큰 차이가 없는 것으로 보이지만 향후 배울 Mixin과 Generic, Viewset을 하게 되면 반복되는 로직이 줄어들고 더 간소화된 로직을 보여드릴 수 있을 것 같습니다.

 

긴 글 읽어주셔서 감사합니다