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
This commit is contained in:
Adrian Holovaty 2007-09-14 19:25:37 +00:00
parent 0d52d2b2f9
commit 55d6aebfec
6 changed files with 58 additions and 10 deletions

View File

@ -2,7 +2,7 @@ from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect
from urllib import quote
def user_passes_test(test_func, login_url=None):
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Decorator for views that checks that the user passes the given test,
redirecting to the log-in page if necessary. The test should be a callable
@ -15,20 +15,25 @@ def user_passes_test(test_func, login_url=None):
def _checklogin(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path())))
return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, quote(request.get_full_path())))
_checklogin.__doc__ = view_func.__doc__
_checklogin.__dict__ = view_func.__dict__
return _checklogin
return _dec
login_required = user_passes_test(lambda u: u.is_authenticated())
login_required.__doc__ = (
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
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(),
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
return actual_decorator
def permission_required(perm, login_url=None):
"""

View File

@ -9,10 +9,10 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.utils.translation import ugettext as _
def login(request, template_name='registration/login.html'):
def login(request, template_name='registration/login.html', redirect_field_name=REDIRECT_FIELD_NAME):
"Displays the login form and handles the login action."
manipulator = AuthenticationForm(request)
redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '')
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.POST:
errors = manipulator.get_validation_errors(request.POST)
if not errors:
@ -35,7 +35,7 @@ def login(request, template_name='registration/login.html'):
return render_to_response(template_name, {
'form': oldforms.FormWrapper(manipulator, request.POST, errors),
REDIRECT_FIELD_NAME: redirect_to,
redirect_field_name: redirect_to,
'site_name': current_site.name,
}, context_instance=RequestContext(request))
@ -56,12 +56,12 @@ def logout_then_login(request, login_url=None):
login_url = settings.LOGIN_URL
return logout(request, login_url)
def redirect_to_login(next, login_url=None):
def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"Redirects the user to the login page, passing the given 'next' page"
if not login_url:
from django.conf import settings
login_url = settings.LOGIN_URL
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, next))
return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, next))
def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html',
email_template_name='registration/password_reset_email.html'):

View File

@ -402,11 +402,29 @@ introduced in Python 2.4::
def my_view(request):
# ...
In the Django development version, ``login_required`` also takes an optional
``redirect_field_name`` parameter. Example::
from django.contrib.auth.decorators import login_required
def my_view(request):
# ...
my_view = login_required(redirect_field_name='redirect_to')(my_view)
Again, an equivalent example of the more compact decorator syntax introduced in Python 2.4::
from django.contrib.auth.decorators import login_required
@login_required(redirect_field_name='redirect_to')
def my_view(request):
# ...
``login_required`` does the following:
* If the user isn't logged in, redirect to ``settings.LOGIN_URL``
(``/accounts/login/`` by default), passing the current absolute URL
in the query string as ``next``. For example:
in the query string as ``next`` or the value of ``redirect_field_name``.
For example:
``/accounts/login/?next=/polls/3/``.
* If the user is logged in, execute the view normally. The view code is
free to assume the user is logged in.

View File

@ -250,6 +250,22 @@ class ClientTest(TestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['user'].username, 'testclient')
def test_view_with_login_and_custom_redirect(self):
"Request a page that is protected with @login_required(redirect_field_name='redirect_to')"
# Get the page without logging in. Should result in 302.
response = self.client.get('/test_client/login_protected_view_custom_redirect/')
self.assertRedirects(response, 'http://testserver/accounts/login/?redirect_to=/test_client/login_protected_view_custom_redirect/')
# Log in
login = self.client.login(username='testclient', password='password')
self.failUnless(login, 'Could not log in')
# Request a page that requires a login
response = self.client.get('/test_client/login_protected_view_custom_redirect/')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['user'].username, 'testclient')
def test_view_with_bad_login(self):
"Request a page that is protected with @login, but use bad credentials"

View File

@ -13,6 +13,7 @@ urlpatterns = patterns('',
(r'^form_view/$', views.form_view),
(r'^form_view_with_template/$', views.form_view_with_template),
(r'^login_protected_view/$', views.login_protected_view),
(r'^login_protected_view_custom_redirect/$', views.login_protected_view_changed_redirect),
(r'^session_view/$', views.session_view),
(r'^broken_view/$', views.broken_view),
(r'^mail_sending_view/$', views.mail_sending_view),

View File

@ -122,6 +122,14 @@ def login_protected_view(request):
return HttpResponse(t.render(c))
login_protected_view = login_required(login_protected_view)
def login_protected_view_changed_redirect(request):
"A simple view that is login protected with a custom redirect field set"
t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
c = Context({'user': request.user})
return HttpResponse(t.render(c))
login_protected_view_changed_redirect = login_required(redirect_field_name="redirect_to")(login_protected_view_changed_redirect)
def session_view(request):
"A view that modifies the session"
request.session['tobacconist'] = 'hovercraft'