summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis Leidel <jannis@leidel.info>2010-09-10 19:38:57 +0000
committerJannis Leidel <jannis@leidel.info>2010-09-10 19:38:57 +0000
commitbb00b2839980145984c487410fc65fbc0c94be3d (patch)
treed1e0df19d3d6195ac80d149e54e93282879f0859
parent27265f70a18ab8fb4bfacad0cdebe170c342054c (diff)
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
-rw-r--r--django/contrib/auth/decorators.py3
-rw-r--r--django/contrib/auth/tests/decorators.py30
-rw-r--r--django/contrib/auth/tests/urls.py4
-rw-r--r--django/contrib/auth/tests/views.py29
-rw-r--r--docs/topics/auth.txt17
5 files changed, 55 insertions, 28 deletions
diff --git a/django/contrib/auth/decorators.py b/django/contrib/auth/decorators.py
index 09dcf42e42..7d7a0cddb7 100644
--- a/django/contrib/auth/decorators.py
+++ b/django/contrib/auth/decorators.py
@@ -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:
diff --git a/django/contrib/auth/tests/decorators.py b/django/contrib/auth/tests/decorators.py
index 7efd9d8ccf..0240a76eb7 100644
--- a/django/contrib/auth/tests/decorators.py
+++ b/django/contrib/auth/tests/decorators.py
@@ -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.
@@ -22,4 +22,24 @@ class LoginRequiredTestCase(TestCase):
"""
def normal_view(request):
pass
- login_required(normal_view) \ No newline at end of file
+ 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/') \ No newline at end of file
diff --git a/django/contrib/auth/tests/urls.py b/django/contrib/auth/tests/urls.py
index f94b8daa7f..c6252ed2de 100644
--- a/django/contrib/auth/tests/urls.py
+++ b/django/contrib/auth/tests/urls.py
@@ -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/')),
)
diff --git a/django/contrib/auth/tests/views.py b/django/contrib/auth/tests/views.py
index d894e6dafd..6b8efad894 100644
--- a/django/contrib/auth/tests/views.py
+++ b/django/contrib/auth/tests/views.py
@@ -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)
diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt
index 4a6e30fc00..00b95ba085 100644
--- a/docs/topics/auth.txt
+++ b/docs/topics/auth.txt
@@ -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'),