9

I'm trying to redirect a user to a url containing his username (like http://domain/username/), and trying to figure out how to do this. I'm using django.contrib.auth for my user management, so I've tried using LOGIN_REDIRECT_URL in the settings:

LOGIN_REDIRECT_URL = '/%s/' % request.user.username # <--- fail..

but it only seems to accept fixed strings, rather than something that'll be determined after the user is logged in. How can I still accomplish this?

sa125
  • 28,121
  • 38
  • 111
  • 153

4 Answers4

19

A solution, is to redirect to a static route like '/userpage/' and have that redirect to the final dynamic page.

But I think the real solution is to make a new view that does what you really want.

from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            HttpResponseRedirect('/%s/'%username) 
        else:
            # Return a 'disabled account' error message
    else:
        # Return an 'invalid login' error message.

http://docs.djangoproject.com/en/dev/topics/auth/#authentication-in-web-requests

for more information about rewriting the view. This is how the docs say to override this kind of thing.

emeryc
  • 825
  • 7
  • 8
  • 3
    I prefer the first suggestion of redirecting from the static /userpage/. That way, you can still use the login view from `django.contrib.auth.views`, which might be more robust than a hand rolled view. – Alasdair Oct 22 '09 at 17:32
  • as I'm trying to simplify urls and minimize redirects, your solution seems like the way to go. thanks! – sa125 Oct 23 '09 at 10:44
  • What a simple and brilliant answer that solves my exact question. I feel ashamed for not thinking of this. enjoy your internet point. – Esteban Apr 19 '13 at 01:18
8

With the class-based django.contrib.auth.views.LoginView, you can now simply override get_success_url:

urls.py:

url(r'^login$', MyLoginView.as_view(), name='login'),
url(r'^users/(?P<username>[a-zA-Z0-9]+)$', MyAccountView.as_view(), name='my_account'),

views.py

class MyLoginView(LoginView):

    def get_success_url(self):
        return reverse('my_account', args=[self.request.user.username])
Flash
  • 15,945
  • 13
  • 70
  • 98
1

Wrap the auth view in your own custom view and redirect to wherever you want if authentication succeeded.

from django.http import HttpResponseRedirect
from django.contrib import auth
from django.core.urlresolvers import reverse

def login(request):
    template_response = auth.views.login(request)

    if isinstance(template_response, HttpResponseRedirect) and template_response.url == '/accounts/profile/':
        return HttpResponseRedirect(reverse('user', args=(request.user.username,)))


    return template_response

Another alternative is to use the query param next to indicate where to redirect to after the login.

<a href="{% url 'login' %}?next={{ request.path }}">sign in</a>
tonyctl
  • 11
  • 2
1

I use django-two-factor-auth login view which provides OTP features for login. Hence I extend from two_factor's LoginView.

In main urls.py:

from two_factor.urls import urlpatterns as tf_urls
urlpatterns = [
  # make sure login is before default two_factor (tf_urls) urls
  # coz first url has higher preference
  path('account/login/', MyLoginView.as_view(), name='login'),
  path('', include(tf_urls)),
]

In views.py:

from two_factor.views.core import LoginView
from two_factor.utils import default_device


class MyLoginView(LoginView):

    def get_success_url(self):
        if self.is_otp_setup() is True:
            return reverse('homepage:homepage')

        # otp not setup. redirect to OTP setup page
        else:
            return reverse('two_factor:setup')
        
    def is_otp_setup(self):
        if self.request.user and \
                self.request.user.is_authenticated and \
                default_device(self.request.user):
            return True
        else:
            return False
Aseem
  • 5,848
  • 7
  • 45
  • 69