Django: How to get exception instance in error handlers - python

Django has built-in default views which are used automatically when exceptions such as PermissionDenied, Http404, SuspiciousOperation, etc. are raised. This is a convenient feature of Django which I love, but it seems to have a limitation.
I am raising an exception with a message: raise PermissionDenied('You are not an xyz and have no access to foobar')
Is there a context variable containing the original exception instance available in the templates (i.e. 403.html) called by the original error handlers so that I can access the message?
If not, is it possible to get a hold of the original exception with a custom handler (settings.handler403, etc.) so I can inject it into the context?
NOTE: I believe I can create a custom middleware with process_exception, but I would like to avoid this if possible since my guess is I would be duplicating a lot of existing Django logic and it's cleaner to reuse it. Also, it looks like a custom process_exception would override the logging in django.core.handlers.base amongst other behaviors. Re-implementing all that just for the sake of injecting exception info into an error template seemed kind of silly.

This feature has been implemented as ticket 24733.
In Django 1.9 and later, the exception will be passed to the error handlers.

Related

How to monkeypatch a Python class for an entire Django application?

The main permission checking methods in Django REST Framework, BasePermission's has_permission and has_permission, both return True, effectively making any permission checking allow by default. Since this is counter to a security mindset and OWASP recommendations I would like to fix the implementation locally before reporting a bug. I could fix it for my own classes by subclassing BasePermission but I want to ensure that every subclass of BasePermission used anywhere does deny by default. Can I replace the functionality of these two methods for every subclass in my Django system without actually patching the BasePermission implementation?
To be clear, I am not trying to do this for testing purposes.

Different bugs always raise the same error: ImproperlyConfigured: The included URLconf 'myproject.urls' does not appear to have any patterns in it

I have a pretty standard Django project with several apps, each with its own urls, models, forms, etc...
My issue is that whenever I make a mistake in my code - e.g. writing a wrong name for a model field in a form "fields" attribute - the error raised is always the same:
django.core.exceptions.ImproperlyConfigured: The included URLconf 'myproject.urls' does not appear to have any patterns in it. If you see valid patterns in the file then the issue is probably caused by a circular import.
I would expect the error message to change according to the error made. This not happening makes everything extremely difficult to debug.
Any ideas?
In Django 2.2, the runserver code has been updated. Unfortunately, this appears to have the side effect that some errors are not displayed as clearly as before.
I created ticket 30329 after reading this question. It appears you are facing a similar issue.
When you run a Django project using runserver, Django loads the URL patterns. Usually, inside your URL patterns you import your views. Which in turn import your models and forms.
So if any of these files contains a syntax error or a python error at the top level (see below), this will cause loading the URLs to fail. However, if you scroll up your trace, you should see another error, the actual error that caused the imports to fail. It will say somewhere "during handling of this exception another exception occurred".
However, python is not actually running all the code it imports. A class definition will just cause python to read the class name and its attributes (a method is also an attribute).
When python imports a class, it calls its __new__() method, not its __init__() method or any other method you define. So only errors at the top level of the class (e.g. using unknown variables in the definition of attributes) or errors inside the Meta class will be thrown.
** edit **: fields = ['some_field'] inside the Meta class is indeed run when the class object is created (__new__() method) and Django will check if the field exists in the corresponding model, because it assigns it to the class's _meta attribute.
In other cases, when you say "whenever I make a mistake in my code" that should generally not raise an error because python should not be actually instantiating the form (running its __init__() method) or running any of the methods you write. So you should avoid instantiating any classes at the top level of your code, instantiation should happen inside of functions/methods, then python won't hit these errors.
So check your views.py files to see if you are just importing form classes (from my_forms import MyForm) or if you are also instantiating a form at the top level of your file (form = MyForm(), note the parenthesis) or as an attribute of a class-based view.

Django ATOMIC_REQUESTS not working

So,
We have this Django Rest Framework application that has some View's methods decorated with #transaction.atomic.
Within this app we also have a test which checks this behaviour by mocking an internal call to throw an error while trying to update a model. Currently, the test passes (the changes do not take place due to the error being thrown).
The problem is, we want to drop the decorations and set all transactions to be atomic. In this case we went for the ATOMIC_REQUESTS database configuration flag. But upon doing that, the test now fails (the model gets updated!).
We managed to print out the config.DATABASES value and the ATOMIC_REQUESTS is there, so it should behave accordingly, right? What are we missing?
As for now, this is an issue on Django-Rest-Framework, as documented here: https://github.com/tomchristie/django-rest-framework/issues/2034

Rendering ValidationError from pre_delete signal in admin form?

I'm trying to trigger a nice error that appears in the admin backend when you try to delete a model instance. If I use the following signal to do this, my problem is that it throws a 500 error instead of posting a nice error message inside the form:
#receiver(models.signals.pre_delete, sender=MyInvincibleModel)
def execute_before_delete(sender, instance, using, *args, **kwargs):
# some logic
raise ValidationError("Nooo, I don't want to die!!")
If, however, I raise a ValidationError in the model's clean method, it DOES appear as a nice error message in the form itself. The problem with doing it this way is that I don't know how to make the clean method check to see if an instance is being deleted. If I had a custom ModelForm setup, I could do something like this:
for cleaned_data in self.cleaned_data:
if cleaned_data.get('DELETE', True):
raise ValidationError("Nooo, I don't want to die!!")
But I want to rely on the standard admin forms and prefer to avoid overwriting every single one where deletion might occur.
My question is: how can I make the validation error thrown by the pre-delete signal render nicely in the admin form or, failing that, how can I make the model clean method detect when data is being deleted?
Django: 1.6.1
Python: 3.3
This proved to be quite a bit more difficult than it should have been, but I found a solution by overriding both ModelAdmin.delete_model (in case a user accessed a single instance of the object via the hyperlink) and the delete_selected action (in case the user tried deleting using the change_list) and putting my logic in there.

ATOMIC_REQUEST and Transactions in Django 1.6

Given the following code:
from django.db import transaction
#transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
From my understanding of transactions in Django 1.6 if do_stuff throws an exception, say an IntegrityError, then the transaction will be rolled back right. But since Django itself is calling the view nothing will stop the IntegrityError from rising up the call stack and causing an HTTP 500 error yes? Let's assume that's not what we want, as we want to gracefully handle the error, but still get the rollback functionality.
So I guess the obvious thought is well, don't do that, use transaction.atomic as a context manager that is wrapped in a try except block like the example here:
try:
with transaction.atomic():
generate_relationships()
except IntegrityError:
handle_exception()
Fine. But then if you want to use the Transaction per HTTP Request functionality by setting ATOMIC_REQUEST = True in your db config, which means django will in effect just add the transaction.atomic decorate to your view, which won't catch any exceptions. How is ATOMIC_REQUEST even useful? Why would you ever want to let your Database errors propagate all the way up to the user?
So my question is.
What am I missing here or is my understanding correct?
If I'm correct what is a use case for using ATOMIC_REQUEST? Am I expected to write a urls.hadler500 or should I implement some middleware to catch the errors?
Your understanding is correct. What you're missing is that letting exceptions propagate from your view code (which is quite different from "propagate all the way up to the user") is a perfectly normal thing to do in Django.
You can customize the resulting behavior by making a 500.html template, by overriding handler500, or by making your own custom middleware. In all of those standard cases, using ATOMIC_REQUESTS will do what you want it to do.
If you want to catch exceptions in your view code and handle them specially, you can certainly do that, you'll just have to specify how to handle transactions manually. Using ATOMIC_REQUESTS is just a way to save some boilerplate for the common case, while allowing you to customize the behavior yourself in the uncommon case.

Categories