Refactor exceptions, and always return error response by raising exceptoin

This commit is contained in:
David Avsajanishvili 2013-06-04 10:08:19 +04:00
parent 9db71a7a48
commit 39477b219a
3 changed files with 26 additions and 23 deletions

View File

@ -11,49 +11,50 @@ from rest_framework import status
class APIException(Exception):
"""
Base class for REST framework exceptions.
Subclasses should provide `.status_code` and `.detail` properties.
Subclasses should provide `.status_code` and `.data` properties.
The `.data` is a dictionary that usually contains just one
field: "detail". However, some exception classes may override
it.
"""
pass
def __init__(self, detail=None):
self.data = {'detail': detail or self.default_detail}
class ParseError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = 'Malformed request.'
def __init__(self, detail=None):
self.detail = detail or self.default_detail
class DeserializeError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
def __init__(self, errors):
self.data = dict(errors)
class AuthenticationFailed(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = 'Incorrect authentication credentials.'
def __init__(self, detail=None):
self.detail = detail or self.default_detail
class NotAuthenticated(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = 'Authentication credentials were not provided.'
def __init__(self, detail=None):
self.detail = detail or self.default_detail
class PermissionDenied(APIException):
status_code = status.HTTP_403_FORBIDDEN
default_detail = 'You do not have permission to perform this action.'
def __init__(self, detail=None):
self.detail = detail or self.default_detail
class MethodNotAllowed(APIException):
status_code = status.HTTP_405_METHOD_NOT_ALLOWED
default_detail = "Method '%s' not allowed."
def __init__(self, method, detail=None):
self.detail = (detail or self.default_detail) % method
self.data = {'detail': (detail or self.default_detail) % method}
class NotAcceptable(APIException):
@ -61,7 +62,9 @@ class NotAcceptable(APIException):
default_detail = "Could not satisfy the request's Accept header"
def __init__(self, detail=None, available_renderers=None):
self.detail = detail or self.default_detail
super(NotAcceptable, self).__init__(detail)
# TODO: self.available_renderers not used anywhere
# across the code
self.available_renderers = available_renderers
@ -70,7 +73,7 @@ class UnsupportedMediaType(APIException):
default_detail = "Unsupported media type '%s' in request."
def __init__(self, media_type, detail=None):
self.detail = (detail or self.default_detail) % media_type
self.data = {'detail': (detail or self.default_detail) % media_type}
class Throttled(APIException):
@ -83,9 +86,10 @@ class Throttled(APIException):
self.wait = wait and math.ceil(wait) or None
if wait is not None:
format = detail or self.default_detail + self.extra_detail
self.detail = format % (self.wait, self.wait != 1 and 's' or '')
self.data = {'detail':
format % (self.wait, self.wait != 1 and 's' or '')}
else:
self.detail = detail or self.default_detail
self.data = {'detail': detail or self.default_detail}
class ConfigurationError(Exception):

View File

@ -7,7 +7,7 @@ which allows mixin classes to be composed in interesting ways.
from __future__ import unicode_literals
from django.http import Http404
from rest_framework import status
from rest_framework import status, exceptions
from rest_framework.response import Response
from rest_framework.request import clone_request
import warnings
@ -55,7 +55,7 @@ class CreateModelMixin(object):
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
raise exceptions.DeserializeError(serializer.errors)
def get_success_headers(self, data):
try:
@ -132,7 +132,7 @@ class UpdateModelMixin(object):
self.post_save(self.object, created=created)
return Response(serializer.data, status=success_status_code)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
raise exceptions.DeserializeError(serializer.errors)
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True

View File

@ -283,8 +283,7 @@ class APIView(View):
exc.status_code = status.HTTP_403_FORBIDDEN
if isinstance(exc, exceptions.APIException):
return Response({'detail': exc.detail},
status=exc.status_code,
return Response(exc.data, status=exc.status_code,
exception=True)
elif isinstance(exc, Http404):
return Response({'detail': 'Not found'},