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.
Related
As of flask 1.1.x, it is easy to return a JSON response body along with an HTTP success code, such as
return {"success": 1, "message": "You did it!"}, 200
However, returning an HTTP failure status the same way
return {"success": 0, "message": "You screwed up."}, 400
only seems to return a response header and message, (e.g. HTTP/1.0 INVALID REQUEST)
The Content-type header (correctly) says application/json, but, the body is empty. This happens for any non-2xx class status code.
Flask documentation implies I should be able to do this, but, nothing I've tried seems to work. This includes creating specialized error handlers like
#app.errorhandler(400)
def custom400(error):
return jsonify({'message': error})
and then calling abort(400, 'my error message'), which doesn't work since the error argument to the handler isn't the string passed to abort, but, is always an error object of whatever type the HTTP error is (e.g. 410 -> <GONE Gone>.
Is this "normal" HTTP response behaviour, or is flask doing something weird?
It turns out this is more PEBKAC than anything else. I had set a breakpoint inside my $.ajax.error handler, looking at the returned response in the browser (chrome) debug window when the breakpoint fired.
But,the body of the response isn't made available to the debug window until AFTER this handler exists. Once I continued execution of the error handler, the JSON response body is came through as expected.
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 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)
I am trying to redirect my 404 to a external URL like this:
#app.route('404')
def http_error_handler(error):
return flask.redirect("http://www.exemple.com/404"), 404
but it does not work. I keep getting:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
You should try something like this:
from flask import render_template
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
Source http://flask.pocoo.org/docs/1.0/patterns/errorpages/
You cannot do this - the user-agent (in most cases, a browser) looks at the status code that is returned to determine what to do. When you return a 404 status code what you are saying to the user-agent is, "I don't know what this thing is you are requesting" and the user-agent can then:
Display what you return in the body of the response
Display its own error message to the end user
Do some combination of the above two options
redirect actually creates a little HTML response (via werkzeug.exceptions), which normally the end user doesn't see because the user-agent follows the Location header when it sees the 302 response. However, you override the status code when you provide your own status code (404).
The fix is to either:
Remove the status code (at the cost of sending the wrong signal to the end user, potentially)
or Send a 404 with a meta:refresh and / or JavaScript redirect (slightly better, still confusing):
return redirect("/where-ever"), 404, {"Refresh": "1; url=/where-ever"}
Try this instead of a route
from flask import request
#app.errorhandler(404)
def own_404_page(error):
pageName = request.args.get('url')
print(pageName)
print(error)
f = open('erreur404.tpl')
return f.read()
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.