简体   繁体   中英

Add custom fields to Django rest_framework APIException

I am subclassing Django's rest framework APIException class to create custom API exceptions. For example, one of my exceptions look like this:

class Unauthorized(APIException):
    status_code = 401
    default_detail = 'You have to login first.'
    default_code = 'ERR_UNAUTHORIZED'

And I've written a custom exception handler to modify key names. This is the part in my exception handler that deals with these kinds of exceptions:

def custom_exception_handler(exc, context):
     response.data['code'] = response.data['detail'].code
     response.data['message'] = response.data['detail']
     print(response.data)
     del response.data['detail']
     return response

As a result, the output for my exceptions looks like this :

{
    "code": "ERR_UNAUTHORIZED",
    "message": "You have to login first."
}

What I need to do is that I want to add a new field to my exceptions so that my exception output becomes like the below example:

{
    "code": "ERR_UNAUTHORIZED",
    "message": "You have to login first.",
    "extra" : "{ "description" : "extra info" }"
}

And in my views, I want to throw this exception like this :

raise Unauthorized(extra={ "description" : "extra info" })

I'm quite new to Django rest_framework and I've searched about this and also tried to add the "another field" to my custom exception class fields but that couldn't solve my problem. Are there any ways to do something like this?

Try like this

def custom_exception_handler(exc, context):
     response.data['code'] = response.data['detail'].code
     response.data['message'] = response.data['detail']

     response.data['another_field'] = { "description" : "extra info" }

     print(response.data)
     del response.data['detail']
     return response

Hope this helps you....

Additional Answer

class Unauthorized(Exception):
    def __init__(self, message, errors):

        # Call the base class constructor with the parameters it needs
        super(ValidationError, self).__init__(message)

        # Now for your custom code...
        self.errors = errors

Raise the exception where you want

raise Unauthorized("Your message")

And catch the exception

try:
    ...
except Unauthorized as e:
    print(str(e))

I found an answer myself (which is not really clean). We can throw exceptions in our serializers like below:

 raise serializers.ValidationError({"info" : "test info"})

And in the custom exception handler we can handle this scenario like this:

def custom_exception_handler(exc, context):

    response = exception_handler(exc, context)

    if isinstance(exc, ValidationError): 
        resp_copy = response.data
        del response.data
        response.data = {}
        if(response.status_code == 400):
            response.data['code'] = 'ERR_UNAUTHORIZED'
            response.data['message'] = 'some errors occurred'
            response.data['extra'] = {}
            for key in resp_copy:
                response.data['extra'][key] = resp_copy[key]

The output will be in the form below:

{
    "code": "ERR_UNAUTHORIZED",
    "message": "some errors occurred",
    "extra": {
        "info": [
            "test info"
        ]
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM