Django REST 프레임 워 크 이상 처리

앞 에 쓰다
이틀 간 DRF 에 필요 한 것 이 무엇 인지,아직 말 하지 못 한 기초적인 지식 이 무엇 인지 고민 해 왔 다.어제 로그 와 관련 된 기능 을 쓰 고 이상 처리 와 관련 된 기능 이 있다 는 생각 이 들 었 다.사실 이전 프로젝트 초기 에는 통 일 된 이상 포획 수단 이 없 었 다.DRF 가 가지 고 있 는 이상 이 대부분의 기능 을 만족 시 킬 수도 있 고 게 을 러 서 비교적 거 친 방식 으로 상태 코드 500 으로 이상 을 던 진 다음 로그 에서 모든 이상 정 보 를 볼 수 있 습 니 다.이렇게 하면 코드 가 튼튼 하지 않 습 니 다.전단 이 호출 될 때 알 수 없 는 500 도 우호 적 이지 않 기 때문에 오늘 은 이상 한 관련 지식 을 보충 하 겠 습 니 다.
DRF 이상 처리
1.DRF 에서 흔히 볼 수 있 는 이상
  • AuthenticationFailed/NotAuthenticated 일반 이 이상 상태 코드 는"401 Unauthenticated"로 로그 인 권한 이 없 을 때 되 돌아 오 며 사용자 정의 로그 인 할 때 사용 할 수 있 습 니 다
  • Permission Denied 는 보통 감정 권 에 사용 되 고 일반 상태 코드 는'403 Forbidden'입 니 다
  • ValidationError 일반 상태 코드 는'400 Bad Request'이 고 주로 serializers 에서 필드 에 대한 검증 입 니 다.예 를 들 어 필드 유형 에 대한 검증,필드 길이 의 검증 과 사용자 정의 필드 형식 에 대한 검증 입 니 다
  • 2.사용자 정의 이상
    이상 에 대한 정의 의 주요 아 이 디 어 는 ValidationError 에서 나 왔 습 니 다.이상 반환 형식 을 통일 하여 전단 에서 유사 한 이상 을 통일 적 으로 처리 할 수 있 습 니 다.
    사용자 정의 이상
    
    #    utils/custom_exception.py
    
    class CustomException(Exception):
        _default_code = 400
    
        def __init__(
            self,
            message: str = "",
            status_code=status.HTTP_400_BAD_REQUEST,
            data=None,
            code: int = _default_code,
        ):
    
            self.code = code
            self.status = status_code
            self.message = message
            if data is None:
                self.data = {"detail": message}
            else:
                self.data = data
    
        def __str__(self):
            return self.message
    
    
    사용자 정의 이상 처리
    
    # utils/custom_exception.py
    from rest_framework.views import exception_handler
    
    def custom_exception_handler(exc, context):
        # Call REST framework's default exception handler first,
        # to get the standard error response.
        
        #         CustomException     ,            
        if isinstance(exc, CustomException):
            return Response(data=exc.data, status=exc.status)
        response = exception_handler(exc, context)
        return response
    
    
    사용자 정의 이상 처리 클래스 설정
    
    REST_FRAMEWORK = {
        # ...
        "EXCEPTION_HANDLER": "utils.custom_exception.custom_exception_handler",
    }
    
    3.사용자 정의 이상 사용
    이전 글 의 인 터 페 이 스 를 사용 하여 사용자 정의 이상 처 리 를 테스트 합 니 다.
    
    class ArticleViewSet(viewsets.ModelViewSet):
        """
                  API  。
        """
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
    
        @action(detail=False, methods=["get"], url_name="exception", url_path="exception")
        def exception(self, request, *args, **kwargs):
            #      demo
            logger.error("     ")
            raise CustomException(data={"detail": "     "})
    
    
    4.검증 결과
    
    $ curl -H 'Accept: application/json; indent=4' -u admin:admin http://127.0.0.1:8000/api/article/exception/
    {
        "detail": "     "
    }
    
    이상 처리 진급
    위의 코드 는 90%의 수 요 를 만족 시 킬 수 있다 고 하지만 잘못된 정의 가 너무 광범 위 하 다.관리 오 류 를 집중 적 으로 정의 하기 어렵 습 니 다.흔히 볼 수 있 는 프로젝트 에서 사용자 정의 이상 과 비교 하 는 장점 은 유연성 입 니 다.그러나 코드 에서 던 진 이상 이 점점 많아 지면 서 구석구석 에 흩 어 져 업데이트 유지 에 불리 합 니 다.따라서 코드 를 수정 하고 이상 에 대해 통 일 된 정 의 를 내 리 는 동시에 사용자 정의 로 HTTP 상태 코드 를 되 돌려 주 는 것 도 지원 합 니 다.
    1.사용자 정의 이상 수정
    
    # utils/custom_exception.py
    
    class CustomException(Exception):
        #    code
        default_code = 400
        #     message
        default_message = None
    
        def __init__(
                self,
                status_code=status.HTTP_400_BAD_REQUEST,
                code: int = None,
                message: str = None,
                data=None,
        ):
            self.status = status_code
            self.code = self.default_code if code is None else code
            self.message = self.default_message if message is None else message
    
            if data is None:
                self.data = {"detail": self.message, "code": self.code}
            else:
                self.data = data
    
        def __str__(self):
            return str(self.code) + self.message
    
    
    2.더 많은 이상 사용자 정의
    
    class ExecuteError(CustomException):
        """    """
        default_code = 500
        default_message = "    "
    
    
    class UnKnowError(CustomException):
        """    """
        default_code = 500
        default_message = "    "
    3.테스트 인터페이스 추가
    
    class ArticleViewSet(viewsets.ModelViewSet):
        """
                  API  。
        """
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
    
        @action(detail=False, methods=["get"], url_name="exception", url_path="exception")
        def exception(self, request, *args, **kwargs):
            #      demo
            logger.error("     ")
            raise CustomException(data={"detail": "     "})
    
        @action(detail=False, methods=["get"], url_name="unknown", url_path="unknown")
        def unknown(self, request, *args, **kwargs):
            #      demo
            logger.error("    ")
            raise UnknownError()
    
        @action(detail=False, methods=["get"], url_name="execute", url_path="execute")
        def execute(self, request, *args, **kwargs):
            #      demo
            logger.error("    ")
            raise ExecuteError()
    
    
    4.검증 결과
    
    curl -H 'Accept: application/json; indent=4' -u admin:admin http://127.0.0.1:8000/api/article/unknown/
    {
        "detail": "    ",
        "code": 500
    }
    $ curl -H 'Accept: application/json; indent=4' -u admin:admin http://127.0.0.1:8000/api/article/execute/
    {
        "detail": "    ",
        "code": 500
    }
    
    총결산
    사용자 정의 이상 처리 함 수 는 사용자 정의 이상 을 처리 한 후에 rest 를 계속 실행 해 야 합 니 다.framework.views.exception_handler,이 곳 의 실행 은 기 존의 이상 처 리 를 호 환 해 야 하기 때 문 입 니 다.DRF 와 관련 된 이상 처리 논 리 를 붙 여 보 겠 습 니 다.
    이 처리 함 수 는 APIException 및 Django 내부 Http 404 Permission Denied 를 기본적으로 처리 합 니 다.다른 이상 은 None 으로 돌아 가 DRF 500 의 오 류 를 촉발 합 니 다.
    
    def exception_handler(exc, context):
        """
        Returns the response that should be used for any given exception.
    
        By default we handle the REST framework `APIException`, and also
        Django's built-in `Http404` and `PermissionDenied` exceptions.
    
        Any unhandled exceptions may return `None`, which will cause a 500 error
        to be raised.
        """
        if isinstance(exc, Http404):
            exc = exceptions.NotFound()
        elif isinstance(exc, PermissionDenied):
            exc = exceptions.PermissionDenied()
    
        if isinstance(exc, exceptions.APIException):
            headers = {}
            if getattr(exc, 'auth_header', None):
                headers['WWW-Authenticate'] = exc.auth_header
            if getattr(exc, 'wait', None):
                headers['Retry-After'] = '%d' % exc.wait
    
            if isinstance(exc.detail, (list, dict)):
                data = exc.detail
            else:
                data = {'detail': exc.detail}
    
            set_rollback()
            return Response(data, status=exc.status_code, headers=headers)
    
        return None
    참고 자료
    Django REST 프레임 워 크 이상 문서
    Django 이상 문서
    Django REST framework 이상 처리 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 Django REST framework 이상 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

    좋은 웹페이지 즐겨찾기