Eivind Uggedal

Login Link in Django with Proper Redirect URL

When using Django's contrib.auth I tend to use the @login_required decorator for restricting access to sensitive views. Whats nice about its implementation is that it will redirect me to a login page and remember the URL I tried to access. After I've successfully logged in it will redirect me to this URL.

Like many people I tend to place a login link at the top of every page if the current user is not authenticated and a log out link otherwise:

{% if user.is_authenticated %}
  <a href="{% url auth_logout %}">Log out</a>
{% else %}
  <a href="{% url auth_login %}">Log in</a>
{% endif %}

The problem with this naive approach is that if I'm on a page with the URL http://example.org/super/duper/ and I click "Log in", I'm taken to whatever the setting LOGIN_REDIRECT_URL dictates (/accounts/profile/ by default) after a successful authentication process. Caring for the usability of my site I naturally wanted a successfull login attempt to take the user back to the page where he or she clicked my "Log in" link.

A neat solution for this problem is to use a context processor to populate each RequestContext with a login URL with the proper redirect parameter set. Note that this requires you to use RequestContext instead of the plain Context in your views when you're rendering templates (I use generic views or a shortcut for render_to_response to handle this).

Implementing such a context processor can easily be achieved by adding the following code to a file called context_processors.py inside one of your Django applications:

from django.utils.http import urlquote
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME

def login_url_with_redirect(request):
    login_url = settings.LOGIN_URL
    path = urlquote(request.get_full_path())
    url = '%s?%s=%s' % (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path)
    return {'login_url': url}

Then you should add this new context processor to the list of template context processors in your settings file:



All that is left to do is to use the new login URL in a template. This could look something like this:

{% if user.is_authenticated %}
  <a href="{% url auth_logout %}">Log out</a>
{% else %}
  <a href="{{ login_url }}">Log in</a>
{% endif %}