J. Choi
J. Choi

Reputation: 1835

Django class-based view to return HttpResponse such as HttpResponseBadRequest

I have a custom Django view class that inherits from the generic DetailView.

The generic DetailView class sequentially calls its methods get_queryset, get_object, and others to generate an object to pass for a Django template.

Moreover, the generic DetailView class raises Http404 exception within these methods to deal with erroneous situations #.

except queryset.model.DoesNotExist:
    raise Http404(_("No %(verbose_name)s found matching the query") %
                  {'verbose_name': queryset.model._meta.verbose_name})

What I am trying to do is simple: I want to return other HTTP status codes to the client if an error is found within these methods. However, because Http404 is the only Django HttpResponse that has a form of exception, it seems like this cannot be achieved easily.

Because HttpResponse is not an exception, I have to return it instead of raising it. Therefore, the customized method becomes the following form.

def get_object(self, queryset=None):
   ...
   try:
      # Get the single item from the filtered queryset
      obj = queryset.get()
   except queryset.model.DoesNotExist:
      return HttpResponseBadRequest("Bad request.")

However, above code does not send HttpResponseBadRequest to the client. Instead, it returns HttpResponseBadRequest as an object for a Django template. The client gets 200 status code with an invalid object for the template.

The only possible solution to think is writing some object-checking code within the Django template. However, I wonder if there is any better way to deal with this problem.

Upvotes: 3

Views: 1369

Answers (1)

Abdul Aziz Barkat
Abdul Aziz Barkat

Reputation: 21807

Since Django 3.2 we now have an exception BadRequest [Django docs] which will be turned into a HttpResponseBadRequest internally when caught, so you can try catching Http404 and raising BadRequest instead:

from django.core.exceptions import BadRequest


class MyView(SomeGenericView):
    ...
    
    def get_object(self, queryset=None):
        try:
            return super().get_object(queryset=queryset)
        except Http404 as e:
            # raise BadRequest("Bad request.") from e
            raise BadRequest("Bad request.")

For some previous version we can try to catch the exception at the dispatch method and return the appropriate response there:

class MyView(SomeGenericView):
    ...
    
    def dispatch(self, request, *args, **kwargs):
        try:
            return super().dispatch(request, *args, **kwargs)
        except Http404:
            return HttpResponseBadRequest("Bad request.")

Upvotes: 1

Related Questions