I would like to catch 500 exception and return a http 4XX exception instead. Using "except Exception" will catch all exceptions which is not desired. I was wondering is there a way to catch only 500 errors
try:
<code>
except <Exception class>:
return http 404 reponse
I searched a lot but couldn't figure out how to do the same. Thanks in advance
I'm not sure that returning 404 instead of 500 is a good idea, but you can acheive this by defining a custom error handler for 500 errors.
In your urls.py:
handler500 = 'mysite.views.my_custom_error_view'
In your views.py:
from django.http import HttpResponse
def my_custom_error_view(request):
"""
Return a 404 response instead of 500.
"""
return HttpResponse("error message", status_code=404)
Related
So just for closed beta and internal testing purposes I'm trying to return the exception with the 400 error in my Django server. Here is an example below of how I am doing this in Django code. I have a partner working on the front-end and they said they can't get the error out of the 400 response. I assumed it'd be in like response.body['error']. How can I send back a 400 with the full error trace in a way that can be pulled out by the front-end?
except Exception as e:
return Response(dict(error=str(e),
user_message=error_message_generic),
status=status.HTTP_400_BAD_REQUEST)
The most common approach is this:
from django.http import JsonResponse, HttpResponseBadRequest
return HttpResponseBadRequest(JsonResponse({
"error": "Malformed request",
# Any other fields you'd want
}))
See more at official docs.
If you are interested on returning specifically a traceback of your back-end exception, you can go this way:
from django.http import JsonResponse, HttpResponseBadRequest
import traceback
...
except Exception as e:
return HttpResponseBadRequest(JsonResponse({
"error": "Malformed request",
"traceback": traceback.format_exc()
}))
traceback.format_exc()
But it's not the best way to do it in all cases. If you are sure, that exception is related to user's input, then traceback wouldn't be so helpful for user. You should better use Serializer, whose validation would be much better. If you're just delivering information about unknown error I'd advise to use HttpResponseServerError and log your exceptions anywhere, to sentry, for example.
What is the difference between abort(400) and returning a response with a 400 status? Is using return bad form for errors?
abort(400, "some error message")
# or
return {'message': "some error message"}, 400
abort raises an error, which an error handler will convert to a response. return returns a response, error handlers don't trigger. It's up to how you want your application to flow.
abort is a wrapper that raises HTTPException classes. Calling abort is the same as raising an exception and Flask will handle both the same way. Returning is not the same as raising an exception and will be handled differently.
Is this:
#login_required
def remove_photo(request):
if request.is_ajax():
try:
BirdPhoto.objects.get( pk = request.POST.get('image_id') ).delete()
except Exception:
raise Exception
return HttpResponse(json.dumps({'msg':'success'}), content_type='application/json')
better than this:
#login_required
def remove_photo(request):
if request.is_ajax():
BirdPhoto.objects.get( pk = request.POST.get('image_id') ).delete()
return HttpResponse(json.dumps({'msg':'success'}), content_type='application/json')
? I have to admit, I don't pay as much attention to error handling and testing as I should. So I just wrote this new function, and I was thinking I should make sure I am handling the errors. Once I kind of got to the basic level of handling errors, I looked at it and said to myself: this isn't really doing anything. It seems to me the two functions will act the same way. This is django, so in production environment the server should catch this and just return a general http response. Am I OK leaving it as the 4 line version and instead of the 6 line version?
The first one is actually worse than the second one. If the second variant raises an exception, it will be a specific exception such as BirdPhoto.DoesNotExist, and your logfiles or the debug view will show you what the exact error is. The first variant will catch the more specific exception, and raise a useless Exception with no error message.
The first rule of exception handling is be specific. You should catch specific exceptions that you know might occur, and specifically handle the error case the way you want. In this case, you know that the id can be invalid, and BirdPhoto.objects.get() might raise a BirdPhoto.DoesNotExist exception. You should catch that exception specifically, and handle it appropriately -- for example by returning a response with status code 404:
#login_required
def remove_photo(request):
if request.is_ajax():
try:
BirdPhoto.objects.get(pk=request.POST.get('image_id')).delete()
except BirdPhoto.DoesNotExist:
return HttpResponse(json.dumps({'msg': 'error'}), status=404, content_type='application/json')
return HttpResponse(json.dumps({'msg':'success'}), content_type='application/json')
Now if the code raises an exception that you did not expect, a 500 Internal Server Error will be returned, and the debug view or logfiles will show the exact error message. You can then fix your code, or if the exception is to be expected, handle the exception appropriately.
First of all, is there a reason not to use DeleteView?
If so, it seems like using get_object_or_404 is the most suitable solution:
#login_required
def remove_photo(request):
if request.is_ajax():
get_object_or_404(BirdPhoto, pk=request.POST.get('image_id')).delete()
return HttpResponse(json.dumps({'msg':'success'}), content_type='application/json')
I have the following function in Django Rest Framework:
#api_view(['GET', 'PUT'])
#permission_classes((permissions.IsAuthenticated,))
def TestView(request, app_id):
return Response({})
It should always return a json response with the empty object, right? Wrong. If I PUT data at this url with media type application/json, and send it malformed json, then Django barfs out a 500 response:
ParseError at /api/v1/test-url
No exception message supplied
I feel like DRF should either raise an exception that I can catch, or send out a 400 error. In fact, the docs even state:
The wrappers also provide behaviour such as returning 405 Method Not
Allowed responses when appropriate, and handling any ParseError
exception that occurs when accessing request.DATA with malformed
input.
So why is my application spitting out a 500 error?
You can configure a custom exception handler and handle the ParseError in there.
I am now a little bit confused.
There are handler404 and handler500 in Django which I can override. I thought, I can do this:
try:
mymodel = MyModel.objects.get(id=someid)
except MyModel.DoesNotExist:
raise Http404
But I would love to know what really caused this 404 - Server Error or just a wrong URL..
how would this be possible? can I have infos about 500 error inside handler404?
in case of 500, handler500 does have a RequestContext and things like {{STATIC_URL}} will stop workingin 500.html. thats why i thought, i will raise 404 instead and email the admin inside 404 handler about error. does this make sense?
The bottom line is this:
In order to generate/cause/raise a 500, you have to request a valid URL.
Its quite simple - the 404 will only be raised if there was no 500 error, because the 500 error would not prevent the link from being valid.
So if its 404, there is no chance for it to also raise a 500; because without you requesting a valid URL, no server side code is run; this thus cannot trigger a 500.
They are mutually exclusive.
In your particular case, here is what happens:
You request /foo/bar/1
This URL is mapped using the url patterns to a view, if it matches - that's it, you have no longer a chance to raise a 404.
The request is passed to the handler - now, at this stage, the request pipeline cannot generate a 404.
There was an error in your view code - now one of two things can happen:
You anticipate this error with a try/except, and then you can raise whatever
exception you like. If this exception also returns a response, then whatever
that response is - that is the error code you are sending back in your reply to the client. So, when you raise Http404, it will return a response, with 404 error code. You can happily return any other response and error code combination.
An error occurs that is not caught by your code, or your code does not return a proper response. In this case, the default exception handler for django will return a response and raise 500. This is the normal/default case.
As you can see from the flow, in any case, to return a 500 response, the URL has to be valid.