Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override exception messages in django rest framework

I am using django class based view and rest framework

object = self.get_object()

In Detail view if object does not exist and i do get request like

/user/10

then i get this response

{"detail": "not found"}

Now i want to customize that response

like

try:
   obj = self.get_object()
except:
   raise Exception("This object does not exist")

But thats not working

like image 733
John Kaff Avatar asked Oct 14 '15 12:10

John Kaff


2 Answers

We can implement a custom exception handler function that returns the custom response in case the object does not exist.

In case a object does not exist, Http404 exception is raised. So, we will check if the exception raised is Http404 and if that is the case, we will return our custom exception message in the response.

from rest_framework.views import exception_handler
from django.http import Http404

def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc, context)

    if isinstance(exc, Http404):  
        custom_response_data = { 
            'detail': 'This object does not exist.' # custom exception message
        }
        response.data = custom_response_data # set the custom response data on response object

    return response

After defining our custom exception handler, we need to add this custom exception handler to our DRF settings.

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
like image 155
Rahul Gupta Avatar answered Oct 21 '22 14:10

Rahul Gupta


You could create a custom exception class as below, and it would raise APIException with a custom message and custom status_code

from rest_framework.serializers import ValidationError
from rest_framework import status



class CustomAPIException(ValidationError):
    """
    raises API exceptions with custom messages and custom status codes
    """
    status_code = status.HTTP_400_BAD_REQUEST
    default_code = 'error'

    def __init__(self, detail, status_code=None):
        self.detail = detail
        if status_code is not None:
            self.status_code = status_code


and in your views,

from rest_framework import status

try:
    obj = self.get_object()
except:
    raise CustomAPIException("This object does not exist", status_code=status.HTTP_404_NOT_FOUND)


The response will be like this
{"detail": "This object does not exist"}

NOTE

the detail parameter of CustomAPIException class takes str,list and dict objects. If you provide a dict object, then it will return that dict as exception response

UPDATE

As @pratibha mentioned, it's not possible to produce desired output if we use this exception class in Serializer's validate() or validate_xxfieldName() methods.

Why this behaviour ?
I wrote a similar answer in SO, here Django REST Framework ValidationError always returns 400

How to obtain desired output within the serializer's validate() method?
Inherit CustomAPIException from rest_framework.exceptions.APIException instead of from rest_framework.serializers.ValidationError
ie,

from rest_framework.exceptions import APIException


class CustomAPIException(APIException):
    # .... code
like image 31
JPG Avatar answered Oct 21 '22 15:10

JPG