mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-04-26 03:53:42 +03:00
Move exception handler out of main view
This commit is contained in:
parent
dce47a11d3
commit
b430503fa6
|
@ -15,8 +15,14 @@ from rest_framework.settings import api_settings
|
||||||
from rest_framework.utils import formatting
|
from rest_framework.utils import formatting
|
||||||
|
|
||||||
|
|
||||||
def get_view_name(cls, suffix=None):
|
def get_view_name(view_cls, suffix=None):
|
||||||
name = cls.__name__
|
"""
|
||||||
|
Given a view class, return a textual name to represent the view.
|
||||||
|
This name is used in the browsable API, and in OPTIONS responses.
|
||||||
|
|
||||||
|
This function is the default for the `VIEW_NAME_FUNCTION` setting.
|
||||||
|
"""
|
||||||
|
name = view_cls.__name__
|
||||||
name = formatting.remove_trailing_string(name, 'View')
|
name = formatting.remove_trailing_string(name, 'View')
|
||||||
name = formatting.remove_trailing_string(name, 'ViewSet')
|
name = formatting.remove_trailing_string(name, 'ViewSet')
|
||||||
name = formatting.camelcase_to_spaces(name)
|
name = formatting.camelcase_to_spaces(name)
|
||||||
|
@ -25,14 +31,53 @@ def get_view_name(cls, suffix=None):
|
||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def get_view_description(cls, html=False):
|
def get_view_description(view_cls, html=False):
|
||||||
description = cls.__doc__ or ''
|
"""
|
||||||
|
Given a view class, return a textual description to represent the view.
|
||||||
|
This name is used in the browsable API, and in OPTIONS responses.
|
||||||
|
|
||||||
|
This function is the default for the `VIEW_DESCRIPTION_FUNCTION` setting.
|
||||||
|
"""
|
||||||
|
description = view_cls.__doc__ or ''
|
||||||
description = formatting.dedent(smart_text(description))
|
description = formatting.dedent(smart_text(description))
|
||||||
if html:
|
if html:
|
||||||
return formatting.markup_description(description)
|
return formatting.markup_description(description)
|
||||||
return description
|
return description
|
||||||
|
|
||||||
|
|
||||||
|
def exception_handler(exc):
|
||||||
|
"""
|
||||||
|
Returns the response that should be used for any given exception.
|
||||||
|
|
||||||
|
By default we handle the REST framework `APIException`, and also
|
||||||
|
Django's builtin `Http404` and `PermissionDenied` exceptions.
|
||||||
|
|
||||||
|
Any unhandled exceptions may return `None`, which will cause a 500 error
|
||||||
|
to be raised.
|
||||||
|
"""
|
||||||
|
if isinstance(exc, exceptions.APIException):
|
||||||
|
headers = {}
|
||||||
|
if getattr(exc, 'auth_header', None):
|
||||||
|
headers['WWW-Authenticate'] = exc.auth_header
|
||||||
|
if getattr(exc, 'wait', None):
|
||||||
|
headers['X-Throttle-Wait-Seconds'] = '%d' % exc.wait
|
||||||
|
|
||||||
|
return Response({'detail': exc.detail},
|
||||||
|
status=exc.status_code,
|
||||||
|
headers=headers)
|
||||||
|
|
||||||
|
elif isinstance(exc, Http404):
|
||||||
|
return Response({'detail': 'Not found'},
|
||||||
|
status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
elif isinstance(exc, PermissionDenied):
|
||||||
|
return Response({'detail': 'Permission denied'},
|
||||||
|
status=status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
|
# Note: Unhandled exceptions will raise a 500 error.
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class APIView(View):
|
class APIView(View):
|
||||||
settings = api_settings
|
settings = api_settings
|
||||||
|
|
||||||
|
@ -303,34 +348,24 @@ class APIView(View):
|
||||||
Handle any exception that occurs, by returning an appropriate response,
|
Handle any exception that occurs, by returning an appropriate response,
|
||||||
or re-raising the error.
|
or re-raising the error.
|
||||||
"""
|
"""
|
||||||
if isinstance(exc, exceptions.Throttled) and exc.wait is not None:
|
|
||||||
# Throttle wait header
|
|
||||||
self.headers['X-Throttle-Wait-Seconds'] = '%d' % exc.wait
|
|
||||||
|
|
||||||
if isinstance(exc, (exceptions.NotAuthenticated,
|
if isinstance(exc, (exceptions.NotAuthenticated,
|
||||||
exceptions.AuthenticationFailed)):
|
exceptions.AuthenticationFailed)):
|
||||||
# WWW-Authenticate header for 401 responses, else coerce to 403
|
# WWW-Authenticate header for 401 responses, else coerce to 403
|
||||||
auth_header = self.get_authenticate_header(self.request)
|
auth_header = self.get_authenticate_header(self.request)
|
||||||
|
|
||||||
if auth_header:
|
if auth_header:
|
||||||
self.headers['WWW-Authenticate'] = auth_header
|
exc.auth_header = auth_header
|
||||||
else:
|
else:
|
||||||
exc.status_code = status.HTTP_403_FORBIDDEN
|
exc.status_code = status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
if isinstance(exc, exceptions.APIException):
|
response = exception_handler(exc)
|
||||||
return Response({'detail': exc.detail},
|
|
||||||
status=exc.status_code,
|
if response is None:
|
||||||
exception=True)
|
|
||||||
elif isinstance(exc, Http404):
|
|
||||||
return Response({'detail': 'Not found'},
|
|
||||||
status=status.HTTP_404_NOT_FOUND,
|
|
||||||
exception=True)
|
|
||||||
elif isinstance(exc, PermissionDenied):
|
|
||||||
return Response({'detail': 'Permission denied'},
|
|
||||||
status=status.HTTP_403_FORBIDDEN,
|
|
||||||
exception=True)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
response.exception = True
|
||||||
|
return response
|
||||||
|
|
||||||
# Note: session based authentication is explicitly CSRF validated,
|
# Note: session based authentication is explicitly CSRF validated,
|
||||||
# all other authentication is CSRF exempt.
|
# all other authentication is CSRF exempt.
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
|
|
Loading…
Reference in New Issue
Block a user