Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #5394 -- REDIRECT_FIELD_NAME is now configurable. Thanks, Petr …

…Marhoun, DavidReynolds and effbot

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6206 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 55d6aebfecb527d64f50e608bb51cb5ea81f4c62 1 parent 0d52d2b
Adrian Holovaty authored September 14, 2007
13  django/contrib/auth/decorators.py
@@ -2,7 +2,7 @@
2 2
 from django.http import HttpResponseRedirect
3 3
 from urllib import quote
4 4
 
5  
-def user_passes_test(test_func, login_url=None):
  5
+def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
6 6
     """
7 7
     Decorator for views that checks that the user passes the given test,
8 8
     redirecting to the log-in page if necessary. The test should be a callable
@@ -15,20 +15,25 @@ def _dec(view_func):
15 15
         def _checklogin(request, *args, **kwargs):
16 16
             if test_func(request.user):
17 17
                 return view_func(request, *args, **kwargs)
18  
-            return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path())))
  18
+            return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, quote(request.get_full_path())))
19 19
         _checklogin.__doc__ = view_func.__doc__
20 20
         _checklogin.__dict__ = view_func.__dict__
21 21
 
22 22
         return _checklogin
23 23
     return _dec
24 24
 
25  
-login_required = user_passes_test(lambda u: u.is_authenticated())
26  
-login_required.__doc__ = (
  25
+def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
27 26
     """
28 27
     Decorator for views that checks that the user is logged in, redirecting
29 28
     to the log-in page if necessary.
30 29
     """
  30
+    actual_decorator = user_passes_test(
  31
+        lambda u: u.is_authenticated(),
  32
+        redirect_field_name=redirect_field_name
31 33
     )
  34
+    if function:
  35
+        return actual_decorator(function)
  36
+    return actual_decorator
32 37
 
33 38
 def permission_required(perm, login_url=None):
34 39
     """
10  django/contrib/auth/views.py
@@ -9,10 +9,10 @@
9 9
 from django.contrib.auth import REDIRECT_FIELD_NAME
10 10
 from django.utils.translation import ugettext as _
11 11
 
12  
-def login(request, template_name='registration/login.html'):
  12
+def login(request, template_name='registration/login.html', redirect_field_name=REDIRECT_FIELD_NAME):
13 13
     "Displays the login form and handles the login action."
14 14
     manipulator = AuthenticationForm(request)
15  
-    redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '')
  15
+    redirect_to = request.REQUEST.get(redirect_field_name, '')
16 16
     if request.POST:
17 17
         errors = manipulator.get_validation_errors(request.POST)
18 18
         if not errors:
@@ -35,7 +35,7 @@ def login(request, template_name='registration/login.html'):
35 35
 
36 36
     return render_to_response(template_name, {
37 37
         'form': oldforms.FormWrapper(manipulator, request.POST, errors),
38  
-        REDIRECT_FIELD_NAME: redirect_to,
  38
+        redirect_field_name: redirect_to,
39 39
         'site_name': current_site.name,
40 40
     }, context_instance=RequestContext(request))
41 41
 
@@ -56,12 +56,12 @@ def logout_then_login(request, login_url=None):
56 56
         login_url = settings.LOGIN_URL
57 57
     return logout(request, login_url)
58 58
 
59  
-def redirect_to_login(next, login_url=None):
  59
+def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
60 60
     "Redirects the user to the login page, passing the given 'next' page"
61 61
     if not login_url:
62 62
         from django.conf import settings
63 63
         login_url = settings.LOGIN_URL
64  
-    return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, next))
  64
+    return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, next))
65 65
 
66 66
 def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html',
67 67
         email_template_name='registration/password_reset_email.html'):
20  docs/authentication.txt
@@ -402,11 +402,29 @@ introduced in Python 2.4::
402 402
     def my_view(request):
403 403
         # ...
404 404
 
  405
+In the Django development version, ``login_required`` also takes an optional
  406
+``redirect_field_name`` parameter. Example::
  407
+    
  408
+    from django.contrib.auth.decorators import login_required
  409
+
  410
+    def my_view(request):
  411
+        # ...
  412
+    my_view = login_required(redirect_field_name='redirect_to')(my_view)
  413
+
  414
+Again, an equivalent example of the more compact decorator syntax introduced in Python 2.4::
  415
+    
  416
+    from django.contrib.auth.decorators import login_required
  417
+
  418
+    @login_required(redirect_field_name='redirect_to')
  419
+    def my_view(request):
  420
+        # ...
  421
+
405 422
 ``login_required`` does the following:
406 423
 
407 424
     * If the user isn't logged in, redirect to ``settings.LOGIN_URL``
408 425
       (``/accounts/login/`` by default), passing the current absolute URL
409  
-      in the query string as ``next``. For example:
  426
+      in the query string as ``next`` or the value of ``redirect_field_name``. 
  427
+      For example:
410 428
       ``/accounts/login/?next=/polls/3/``.
411 429
     * If the user is logged in, execute the view normally. The view code is
412 430
       free to assume the user is logged in.
16  tests/modeltests/test_client/models.py
@@ -250,6 +250,22 @@ def test_view_with_login(self):
250 250
         self.assertEqual(response.status_code, 200)
251 251
         self.assertEqual(response.context['user'].username, 'testclient')
252 252
 
  253
+    def test_view_with_login_and_custom_redirect(self):
  254
+        "Request a page that is protected with @login_required(redirect_field_name='redirect_to')"
  255
+        
  256
+        # Get the page without logging in. Should result in 302.
  257
+        response = self.client.get('/test_client/login_protected_view_custom_redirect/')
  258
+        self.assertRedirects(response, 'http://testserver/accounts/login/?redirect_to=/test_client/login_protected_view_custom_redirect/')
  259
+
  260
+        # Log in
  261
+        login = self.client.login(username='testclient', password='password')
  262
+        self.failUnless(login, 'Could not log in')
  263
+
  264
+        # Request a page that requires a login
  265
+        response = self.client.get('/test_client/login_protected_view_custom_redirect/')
  266
+        self.assertEqual(response.status_code, 200)
  267
+        self.assertEqual(response.context['user'].username, 'testclient')
  268
+
253 269
     def test_view_with_bad_login(self):
254 270
         "Request a page that is protected with @login, but use bad credentials"
255 271
 
1  tests/modeltests/test_client/urls.py
@@ -13,6 +13,7 @@
13 13
     (r'^form_view/$', views.form_view),
14 14
     (r'^form_view_with_template/$', views.form_view_with_template),
15 15
     (r'^login_protected_view/$', views.login_protected_view),
  16
+    (r'^login_protected_view_custom_redirect/$', views.login_protected_view_changed_redirect),
16 17
     (r'^session_view/$', views.session_view),
17 18
     (r'^broken_view/$', views.broken_view),
18 19
     (r'^mail_sending_view/$', views.mail_sending_view),
8  tests/modeltests/test_client/views.py
@@ -122,6 +122,14 @@ def login_protected_view(request):
122 122
     return HttpResponse(t.render(c))
123 123
 login_protected_view = login_required(login_protected_view)
124 124
 
  125
+def login_protected_view_changed_redirect(request):
  126
+    "A simple view that is login protected with a custom redirect field set"
  127
+    t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
  128
+    c = Context({'user': request.user})
  129
+    
  130
+    return HttpResponse(t.render(c))
  131
+login_protected_view_changed_redirect = login_required(redirect_field_name="redirect_to")(login_protected_view_changed_redirect)
  132
+
125 133
 def session_view(request):
126 134
     "A view that modifies the session"
127 135
     request.session['tobacconist'] = 'hovercraft'

0 notes on commit 55d6aeb

Please sign in to comment.
Something went wrong with that request. Please try again.