Django middleware catches exception - python

I am using python-social-auth, and I am catching any exceptions using the following middleware:
class ExtendedSocialAuthExceptionMiddleware(SocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if hasattr(social_exceptions, exception.__class__.__name__):
return HttpResponse('error')
else:
raise exception
What I would like to do in this exception handler is redirect the user to the page they came from, and display the exception in a label in that template. How would I do this?

As documented here :
return redirect(url)

Related

How can I reference a user globally in Django for all Exceptions?

I have two questions that correlate.
1) Does django-rest-framework have a way to reference a user globally?
2) Does django / python allow me to change the generic exception class to include this user ID as meta every time it throws?
I know I can create custom exception classes and raise them in code, but what about an exception I don’t correctly handle? For example, let’s say a divide by zero exception is thrown but I didn’t correctly handle it, right now my logs just say “Divide by zero exception”.
Is there a way to update this globally so if a user is logged in it says “Divide by zero exception for user_id {id}“?
class SomeExternalApiHelper:
#staticmethod
def do_api_call():
url = 'https://example.com'
# do api request
try:
home_value = 100 / 0
except Exception as e:
# Exception occurs here, I want to be able to reference user_id, without having
# to pass the user_object all the way down into this call
raise Exception("Something went wrong for user ID {0}".format(user_id))
class AddNewHouse(APIView):
def post(self, request, format=None):
# I can call request.user here and access the user object
SomeExternalApiHelper.do_api_call()
You can create a custom middleware that catches all exceptions, you can then log the exception along with the user
def exception_middleware(get_response):
def middleware(request):
try:
response = get_response(request)
except Exception as e:
# You now have the exception and request.user and can log how you like
raise
return response
return middleware

How to capture middleware exception from other middleware in Django

I coding backend system with Django now, and I want control all exception from Django, so I create one middleware which name is CustomExceptoinMiddleware to control exception.
But sometimes other middleware also raise exception, I hope CustomExceptoinMiddleware can capture it too, but I don't know how to do it.
Can somebody help me?
Thanks in advance!
Python version: 3.7
Django version: 2.2.3
Setting.py
MIDDLEWARE = [
...
"api.core.middleware.CustomExceptoinMiddleware ",
"api.core.middleware.RaiseExcceptionMiddleware",
...
]
# middleware.py
class CustomExceptoinMiddleware(MiddlewareMixin):
def process_exception(self, request, exception):
print(f"Capture exception: {type(exception)}")
class RaiseExcceptionMiddleware(MiddlewareMixin):
def process_request(self, request):
raise KeyError()
You cannot do that. As you may read in documentation (https://docs.djangoproject.com/en/2.2/topics/http/middleware/#process-exception) you can only catch exception from the view. More detailed:
Again, middleware are run in reverse order during the response phase,
which includes process_exception. If an exception middleware returns a
response, the process_exception methods of the middleware classes
above that middleware won’t be called at all.

How to capture exception in django rest framework with django middleware?

Django middleware have a process_exception hook which can be used to capture exception and handler.
But there is some problem while using Django restframe work
class ExceptionHandler(MiddlewareMixin):
#staticmethod
def process_exception(request, exception):
if isinstance(exception, ValidationError):
return Response(data=exception.messages, status=status.HTTP_400_BAD_REQUEST)
For example, I try to use above middleware to capture the ValidationError and return HTTP 400
But it will not work and raise below error
AssertionError: .accepted_renderer not set on Response
It turns out that the rest-framework view layer will add a .accepted_renderer to the response.
If I handle the exception outside view. This attribute will be missed and cause another exception.
So my question is: Is it wrong to handle exception in middleware when using django rest-framework?
What is the correct way to do ?
A better way to do this in Django Rest framework is to create a custom exception handler and replace the default exception handler with your custom handler. For more details on it you can check out the official documentation: http://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling

How to catch any exception in python and print stack trace (DJANGO)

I have like this:
try:
#bunch of code
except:
return HttpResponse....
I want to send an error to client and to print stack trace on console. How can i do that?
You can do something like this
import traceback
from django.http import HttpReponse
def view(request):
try:
#throw exception
except:
tb = traceback.format_exc()
return HttpResponse(tb)
# normal flow
You can create a custom middleware class where you can catch all exceptions:
class ErrorMiddleware(object):
def process_exception(self, request, exception):
# send error
return HttpResponse(...) # or None
and put it on first place to MIDDLEWARE_CLASSES tuple in settings.py.
From middleware process_exception docs:
Django calls process_exception() when a view raises an exception.
process_exception() should return either None or an HttpResponse
object. If it returns an HttpResponse object, the template response
and response middleware will be applied, and the resulting response
returned to the browser. Otherwise, default exception handling kicks
in.
You might want to enable logging of all exceptions How do you log server errors on django sites
and make a custom 500 django error page https://docs.djangoproject.com/en/dev/topics/http/views/#the-500-server-error-view
and you should also make a 500 error page at web server level (apache / nginx) just in case the framework doesn't work.
That way you can "catch" all errors and show a nice error message to the client.

Does Django have exception for an immediate http response?

Django-Tastypie has ImmediateHttpResponse exception which allow to return to the client an immediate response:
raise ImmediateHttpResponse(response='a message')
Django has Http404, but i couldn't find a more universal exception like ImmediateHttpResponse.
What technique do you use to return to client an immediate 400 response?
For example having model:
class Subscriber(Model):
def delete(self, *args, **kwargs):
raise ImmediateHttpResponse('Deleting subcribers is not allowed!')
and trying to delete an object would return to the client a 400 response with the given message.
I think what you want is a middleware which implements a process_exception.
It works like this: you raise an Exception on you view (e.g. ImmediateHttpResponse). If the exception is catched by your middleware, the middleware returns a response, in your case the with a status 400. If you don't catch the exception, Django will catch it in the end, returning a status 500 (server error), or other status.
The simplest example is a middleware that catches Http404. If you catch the exception Http404 in your middleware, you can return any response you want (status 200, 400, etc). If you don't catch (i.e. the process_exception method of you middleware returns None), Django will catch it for you and return a Response with status 404. This is actually the standard way of having your own custom exceptions that you want to respond in a custom way.
It is not an exception, but there is HttpResponseBadRequest, which is your normal HttpResponse but with 400.
The Http404 exception is simply an empty Exception class, there is nothing special about it:
class Http404(Exception):
pass
So you can easily create your own if you must:
class Http400(Exception):
pass
ImmediateHttpResponse isn't that much different than Http404 in that its also a generic Exception but with a specific property, which makes it more like HttpResponseBadRequest:
class ImmediateHttpResponse(TastypieError):
"""
This exception is used to interrupt the flow of processing to immediately
return a custom HttpResponse.
Common uses include::
* for authentication (like digest/OAuth)
* for throttling
"""
_response = HttpResponse("Nothing provided.")
def __init__(self, response):
self._response = response
#property
def response(self):
return self._response

Categories