• 티스토리 홈
  • 프로필사진
    조별하
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
조별하
  • 프로필사진
    조별하
    • 분류 전체보기 (124)
      • 1. 공부 (0)
        • 기술 면접 (0)
      • 2. 웹개발 (7)
        • Java (1)
        • IT 정보 (5)
        • Error 모음 (1)
      • 3. 개인관심 (1)
        • 전자 (1)
      • GITHUB (5)
      • IT 기술 면접 (3)
      • COMPUTER (2)
      • TASK (1)
      • LANGUAGES (20)
        • Python (3)
        • Django (6)
        • Java (7)
        • Node (1)
        • Jsp (2)
        • R (1)
      • 데이터과학 (2)
        • 머신러닝 및 딥러닝 (2)
      • DATABASE (5)
        • Oracle (2)
      • ISSUE (10)
        • Django (4)
        • Drf (2)
        • Javascript (1)
        • Git (1)
      • JAVA 교육 (65)
        • Java (3)
        • Jquery (2)
        • Sql (16)
        • Jdbc (1)
        • Db (2)
        • Jsp (9)
        • myWeb (15)
        • Servlet (4)
        • Spring (12)
        • Crawling (0)
        • Hosting (1)
      • 정보처리산업기사 (1)
      • EDUCATION (2)
        • IoT 서비스 (2)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • [ISSUE] gernerics view, DestroyAPIView 적용
        2023년 05월 05일
        • 조별하
        • 작성자
        • 2023.05.05.:09

        [22.11.20] Try to apply generics DestroyAPIView

        Generics View를 사용하지 않는 이유

        ✔️ DRF로 서버단을 rest_framework가 지원해주는 generics View를 사용하지 않고 APIView만을 이용하여 프로젝트를 진행하기로 결정하였다.

         

        ✔️ 그렇게 결정한 이유는 generics 한 View를 사용하면 코드가 간결해지고 개발하기 편리해지긴 하지만 팀 프로젝트를 진행하며 그렇게 간결해지고 작동되는 로직을 파악하지 않고 무분별하게 사용하는 것을 우려하여 처음에는 자유롭게 customizing이 가능한 APIView를 사용하기로 했다.

         

        APIView로 작성된 Bulk Delete

        ✔️ 항목을 다중으로 삭제하기 위한 기능 개발을 위해 클라이언트 단에서 선택한 항목의 id(식별자)를 리스트로 전달하여 서버 단에서 받아 그 항목들을 모두 삭제하는 로직을 개발하였다.

        클라이언트 단

        function setFetchData(method, body){
            /* Fetch data 셋팅 */
        
            let csrftoken = getCookie('csrftoken');
        
            const data = {
                method: method,
                headers: {
                    'content-type': 'application/json',
                    'X-CSRFToken' : csrftoken,        
                },
                body: JSON.stringify(body)
            }
            return data
        }
        
        function bulkDelete() {
            /* 벌크 삭제 이벤트 */
        
            const data = setFetchData("DELETE", {
                pk_ids: selected_articles, // [1, 2, 3, 4, 5]
            })
        
            fetch(`/api/sites/bulk`, data)
                .then(response => {
                    let status = response.status
        
                    if(status == 200)
                        alert('삭제에 성공하였습니다.')                    
                })
                .then(() => getSiteList())
                .then(() => changeSelected())
                .catch(error   => console.log(error))
        }

         

        서버 단

        # urls.py
        path('sites/bulk', SiteBulkAPIView.as_view())
        
        
        # views.py
        class SiteBulkAPIView(APIView):
            """
            벌크 항목 삭제 api
            """
        
            def delete(self, request):
        
                pk_ids: list = self.request.data.get('pk_ids')
        
                sites = Site.objects.filter(id__in=pk_ids)
        
                for site in sites:
                    site.delete()
        
                return Response({'msg': 'Deleted successfully'}, status=status.HTTP_200_OK)

         

        APIView

        # 상속받은 APIVIEW
        class APIView(View):
        
            # The following policies may be set at either globally, or per-view.
            renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
        
            ...
        
        # APIView가 상속받은 View
        class View:
            """
            Intentionally simple parent class for all views. Only implements
            dispatch-by-method and simple sanity checking.
            """
        
            http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
        
            def dispatch(self, request, *args, **kwargs):
                # Try to dispatch to the right method; if a method doesn't exist,
                # defer to the error handler. Also defer to the error handler if the
                # request method isn't on the approved list.
                if request.method.lower() in self.http_method_names:
                    handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
                return handler(request, *args, **kwargs)

         

        ✔️ 상속받은 APIView가 어떻게 HTTP 메소드에 따라 어떻게 작성한 내부 메서드로 들어와 처리가 될 수 있는지 APIView를 타고 들어가 부모 클래스인 View까지 타고 들어가 코드를 확인해 보니 View클래스에서 http 매소드 명에 따라 작성한 내부 메서드로 핸들링해주고 있었다.

         

        DestroyAPIView로 delete처리 적용

        ✔️ Delete 처리를할 때 rest_framework의 DestroyAPIView로 처리한다고 공식문서를 확인하여 이를 이용하여 로직을 변경해보려 했다.

         

        ✔️ 하지만 DestroyAPiView는 하나의 id(식별자) 값만 path파라미터로 받아 처리를 해주는 클래스이기 때문에 bulk처리에는 적합하지 않았다. 그래서 bulk처리가 아닌 단일 삭제 처리 기능에서 DestroyAPIView를 적용해 보았다.

        출처 : DRF 공식문서

        클라이언트 단

        function deleteSite() {
        
            const data = setFetchData('DELETE', '')
        
            fetch(`/api/sites/${site.id}`, data)
                .then(response => {
                    const status = response.status
        
                    if (status === 200) {
                        console.log('삭제 완료했습니다.')
        
                    } else if (status === 404) {
                        console.log('해당 항목이 존재하지 않습니다.')
        
                    } 
                    return response.json() 
                })
                .catch(error => console.log('Error:', error))
        }

         

        서버 단

        # urls.py
        path('sites/<int:pk>', SiteDetailAPIView.as_view()),
        
        # views.py
        class SiteDetailAPIView(DestroyAPIView):
            """
            항목 단일 삭제 api
            """
        
            queryset = Site.objects.all()
            serializer_class = SiteSerializer

         

        ✔️ 위 와 같이 작성 후 삭제를 시도하면 삭제되는 코드를 작성하지 않았지만 DestroyAPIView를 상속받은 것 만으로 전달받은 pk값을 인식하여 해당하는 데이터를 처리해준다.

         

        DestroyAPIView

        # DestroyAPIView
        class DestroyAPIView(mixins.DestroyModelMixin,
                             GenericAPIView):
            """
            Concrete view for deleting a model instance.
            """
            def delete(self, request, *args, **kwargs):
                return self.destroy(request, *args, **kwargs)
        
        # mixins.DestroyModelMixin
        class DestroyModelMixin:
            """
            Destroy a model instance.
            """
            def destroy(self, request, *args, **kwargs):
                instance = self.get_object()
                self.perform_destroy(instance)
                return Response(status=status.HTTP_204_NO_CONTENT)
        
            def perform_destroy(self, instance):
                instance.delete()
        코드 작성을 하지 않고 처리가 되는 과정을 확인해 보기 위해 상속받은 DestroyAPIView를 확인해 보았다. DestroyAPIView가 또 다른 두 개의 클래스 mixins.DestroyModelMixin와 GenericAPIView를 상속받고 있는데 삭제 처리가 작성되어 있는 DestroyModelMixin 클래스를 타고 들어가 확인해 보면 destroy내부 함수에 perform_destroy로 해당 인스턴스를 삭제하는 코드가 작성된 것을 확인할 수 있다. 즉, 우리는 이 클래스를 상속받아 우리가 작성해야 하는 코드대신 그 안에서 작성된 코드가 실행되어 처리된다는 것을 알 수 있다.

         

         

        저작자표시 (새창열림)

        'ISSUE' 카테고리의 다른 글

        [ISSUE] REST API GET방식에서 POST로의 변경  (0) 2023.04.19
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바