Django context processor throw error on redirect

724 Views Asked by At

I'm using the following context processor to pass context to all my pages, except when the user is not logged in which case it takes him to the login page :

from django.conf import settings
from .models import foo
from django.shortcuts import redirect


def globalVar(request):
    if not request.session.get('user_id') is None:
        return {"foo": foo}
    else:
        return redirect('login')

But the redirect causes an exception for which i didn't find a fix : ValueError: dictionary update sequence element #0 has length 0; 2 is required

Am i not looking in the right place, or is there a way to replace redirect by something else ?

3

There are 3 best solutions below

7
AKX On BEST ANSWER

You can't simply return a redirect from a context processor, since context processors need to return a dict of context variables.

If you really need this functionality in a context processor, you would need to

  • define a custom exception class (that e.g. wraps the response)
  • raise such an exception from the context processor (since you can't return a non-dictionary)
  • catch the custom exception in a Django middleware, unwrap the response and return it

(as an aside, I've written a package that does that – django-safespace)

Instead, if you can, use the login_required decorator (or CBV mixin – see the linked documentation) to make your entire view logged-in-user only.

3
Ahmed I. Elsayed On

EDIT: The above answer assumed something else so I've deleted and replaced with an elaboration of why returning redirect doesn't work in case you want to understand

context = {}
redirect = redirect('login')
context.update(redirect)

This should cause the same error you're getting. Got the idea?

0
Daniele Zanotelli On

I faced a similar issue lately. In a class-based view, method get_context_data, I needed to raise an Exception if certain conditions were not met, and trigger a redirect (while showing an error message using django.messages).

I got this error:

TypeError: context must be a dict rather than HttpResponseRedirect.

I solved it

  • letting the get_context_data method free to raise the error (not catching it here)
  • patching the view dispatch method like this:
    def dispatch(self, request, *args, **kwargs):
        try:
            return super().dispatch(request, *args, **kwargs)
        except Exception as e:
            # use django message to show the error
            messages.error(self.request, message=e)
            # here redirect does work
            return redirect(reverse(...))

Enjoy.