Added login_url argument to login_required decorator. Thanks mhlakhani and ericflo for the report and patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13723 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2010-09-10 19:38:57 +00:00
parent 27265f70a1
commit bb00b28399
5 changed files with 55 additions and 28 deletions

View File

@ -30,13 +30,14 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE
return decorator
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
"""
Decorator for views that checks that the user is logged in, redirecting
to the log-in page if necessary.
"""
actual_decorator = user_passes_test(
lambda u: u.is_authenticated(),
login_url=login_url,
redirect_field_name=redirect_field_name
)
if function:

View File

@ -1,12 +1,12 @@
from unittest import TestCase
from django.contrib.auth.decorators import login_required
from django.contrib.auth.tests.views import AuthViewsTestCase
class LoginRequiredTestCase(TestCase):
class LoginRequiredTestCase(AuthViewsTestCase):
"""
Tests the login_required decorators
"""
urls = 'django.contrib.auth.tests.urls'
def testCallable(self):
"""
Check that login_required is assignable to callable objects.
@ -23,3 +23,23 @@ class LoginRequiredTestCase(TestCase):
def normal_view(request):
pass
login_required(normal_view)
def testLoginRequired(self, view_url='/login_required/', login_url='/login/'):
"""
Check that login_required works on a simple view wrapped in a
login_required decorator.
"""
response = self.client.get(view_url)
self.assertEqual(response.status_code, 302)
self.assert_(login_url in response['Location'])
self.login()
response = self.client.get(view_url)
self.assertEqual(response.status_code, 200)
def testLoginRequiredNextUrl(self):
"""
Check that login_required works on a simple view wrapped in a
login_required decorator with a login_url set.
"""
self.testLoginRequired(view_url='/login_required_login_url/',
login_url='/somewhere/')

View File

@ -1,5 +1,7 @@
from django.conf.urls.defaults import patterns
from django.contrib.auth.urls import urlpatterns
from django.contrib.auth.views import password_reset
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.template import Template, RequestContext
@ -14,5 +16,7 @@ urlpatterns += patterns('',
(r'^logout/custom_query/$', 'django.contrib.auth.views.logout', dict(redirect_field_name='follow')),
(r'^logout/next_page/$', 'django.contrib.auth.views.logout', dict(next_page='/somewhere/')),
(r'^remote_user/$', remote_user_auth_view),
(r'^login_required/$', login_required(password_reset)),
(r'^login_required_login_url/$', login_required(password_reset, login_url='/somewhere/')),
)

View File

@ -36,6 +36,16 @@ class AuthViewsTestCase(TestCase):
settings.LANGUAGE_CODE = self.old_LANGUAGE_CODE
settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
def login(self, password='password'):
response = self.client.post('/login/', {
'username': 'testclient',
'password': password
}
)
self.assertEquals(response.status_code, 302)
self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL))
self.assert_(SESSION_KEY in self.client.session)
class PasswordResetTest(AuthViewsTestCase):
def test_email_not_found(self):
@ -118,15 +128,6 @@ class PasswordResetTest(AuthViewsTestCase):
class ChangePasswordTest(AuthViewsTestCase):
def login(self, password='password'):
response = self.client.post('/login/', {
'username': 'testclient',
'password': password
}
)
self.assertEquals(response.status_code, 302)
self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL))
def fail_login(self, password='password'):
response = self.client.post('/login/', {
'username': 'testclient',
@ -228,16 +229,6 @@ class LoginTest(AuthViewsTestCase):
class LogoutTest(AuthViewsTestCase):
urls = 'django.contrib.auth.tests.urls'
def login(self, password='password'):
response = self.client.post('/login/', {
'username': 'testclient',
'password': password
}
)
self.assertEquals(response.status_code, 302)
self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL))
self.assert_(SESSION_KEY in self.client.session)
def confirm_logged_out(self):
self.assert_(SESSION_KEY not in self.client.session)

View File

@ -713,6 +713,17 @@ The login_required decorator
def my_view(request):
...
.. versionadded:: 1.3
:func:`~django.contrib.auth.decorators.login_required` also takes an
optional ``login_url`` parameter. Example::
from django.contrib.auth.decorators import login_required
@login_required(login_url='/accounts/login/')
def my_view(request):
...
:func:`~django.contrib.auth.decorators.login_required` does the following:
* If the user isn't logged in, redirect to
@ -726,9 +737,9 @@ The login_required decorator
* If the user is logged in, execute the view normally. The view code is
free to assume the user is logged in.
Note that you'll need to map the appropriate Django view to
:setting:`settings.LOGIN_URL <LOGIN_URL>`. For example, using the defaults, add
the following line to your URLconf::
Note that if you don't specify the ``login_url`` parameter, you'll need to map
the appropriate Django view to :setting:`settings.LOGIN_URL <LOGIN_URL>`. For
example, using the defaults, add the following line to your URLconf::
(r'^accounts/login/$', 'django.contrib.auth.views.login'),