« seo findings | seamless data migration part 1 »
May 6, 2009 6:18 p.m.
With django's "batteries included" type of framework, I tend to get caught up with trying to utilize functionality that is already built in. Typically this is more efficient, but sometimes it stands in the way of progress.
Recently, I wanted to add some simple redirect logic to the login process of this site. All I wanted to do was redirect users back to their previous page after successfully logging in. That way if someone was reading a post and wanted to comment, they could log into the site and be redirected back to the post they were reading. Instead of being forced to find it on their own again. Sounds easy enough, right?
My current login page just calls the built in django code from django.contrib.auth.views.login. I remember seeing in the Django Documentation that this code had some redirect capabilities. Sure enough, although limited in my situation because I'm not using my own view. So, I couldn't take advantage of the login_required decorator.
However, I found that views.login() will automagically redirect after successfull login to the URL specified in the 'next' variable. Just supply the value of 'next' as a hidden field on the login form. It could be as simple as this:
<input type="hidden" name="next" value="{{ next }}" />
If 'next' has not been given a value, the variable LOGIN_REDIRECT_URL (default: /accounts/profile) will be used. The default can be changed by setting LOGIN_REDIRECT_URL in the settings.py file.
Since I want the redirect to be dynamic, setting the value of 'next' would have to be done on the fly. I first attempted to grab the HTTP referrer and put it in the place of 'next' in the hidden field on the login page.
<input type="hidden" name="next" value="{{ request.META.HTTP_REFERER }}" />
Well, this doesn't work... Come to find out, views.login() ignores redirects that contain '//' anywhere in it's value. Since there is a '//' in the referrer. Attempting to strip out everything except the path from the referrer turned into a giant black hole.
Since nothing was working out, I decided to create my own login view. This way I could duplicate the built in version, but provide the extra functionality to pass in the referrer and strip it down to the path that I needed for the redirect. While writing this view it dawned on me that I was making this way too complicated.
As it turns out, there was a much easier way to accomplish my goal. So simple... So easy... Why didn't I think of this before? Just pass the value of the current page to the login link and use it for the redirect. All I had to do was change my login links to the following:
<a href="/accounts/login/?next={{ request.META.PATH_INFO }}">login</a>
Looky there... Problem solved! Goes to show you how easy it is to over complicate things sometimes. I was so caught up in using built in code logic on the login form itself that I overlooked the quickest and simplest solution.