Loading django/contrib/auth/decorators.py +3 −3 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ from django.contrib.auth import REDIRECT_FIELD_NAME from django.core.exceptions import PermissionDenied from django.utils.decorators import available_attrs from django.utils.encoding import force_str from django.shortcuts import resolve_url def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): Loading @@ -23,11 +24,10 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE if test_func(request.user): return view_func(request, *args, **kwargs) path = request.build_absolute_uri() # urlparse chokes on lazy objects in Python 3 login_url_as_str = force_str(login_url or settings.LOGIN_URL) resolved_login_url = resolve_url(login_url or settings.LOGIN_URL) # If the login url is the same scheme and net location then just # use the path as the "next" url. login_scheme, login_netloc = urlparse(login_url_as_str)[:2] login_scheme, login_netloc = urlparse(resolved_login_url)[:2] current_scheme, current_netloc = urlparse(path)[:2] if ((not login_scheme or login_scheme == current_scheme) and (not login_netloc or login_netloc == current_netloc)): Loading django/contrib/auth/tests/decorators.py +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ class LoginRequiredTestCase(AuthViewsTestCase): pass login_required(normal_view) def testLoginRequired(self, view_url='/login_required/', login_url=settings.LOGIN_URL): 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. Loading django/contrib/auth/views.py +9 −9 Original line number Diff line number Diff line Loading @@ -7,9 +7,9 @@ from django.conf import settings from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect, QueryDict from django.template.response import TemplateResponse from django.utils.encoding import force_str from django.utils.http import base36_to_int from django.utils.translation import ugettext as _ from django.shortcuts import resolve_url from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.cache import never_cache from django.views.decorators.csrf import csrf_protect Loading Loading @@ -38,16 +38,16 @@ def login(request, template_name='registration/login.html', if request.method == "POST": form = authentication_form(data=request.POST) if form.is_valid(): netloc = urlparse(redirect_to)[1] # Use default setting if redirect_to is empty if not redirect_to: redirect_to = settings.LOGIN_REDIRECT_URL redirect_to = resolve_url(redirect_to) netloc = urlparse(redirect_to)[1] # Heavier security check -- don't allow redirection to a different # host. elif netloc and netloc != request.get_host(): redirect_to = settings.LOGIN_REDIRECT_URL if netloc and netloc != request.get_host(): redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL) # Okay, security checks complete. Log the user in. auth_login(request, form.get_user()) Loading Loading @@ -110,6 +110,7 @@ def logout_then_login(request, login_url=None, current_app=None, extra_context=N """ if not login_url: login_url = settings.LOGIN_URL login_url = resolve_url(login_url) return logout(request, login_url, current_app=current_app, extra_context=extra_context) def redirect_to_login(next, login_url=None, Loading @@ -117,10 +118,9 @@ def redirect_to_login(next, login_url=None, """ Redirects the user to the login page, passing the given 'next' page """ # urlparse chokes on lazy objects in Python 3 login_url_as_str = force_str(login_url or settings.LOGIN_URL) resolved_url = resolve_url(login_url or settings.LOGIN_URL) login_url_parts = list(urlparse(login_url_as_str)) login_url_parts = list(urlparse(resolved_url)) if redirect_field_name: querystring = QueryDict(login_url_parts[4], mutable=True) querystring[redirect_field_name] = next Loading Loading @@ -229,7 +229,7 @@ def password_reset_complete(request, template_name='registration/password_reset_complete.html', current_app=None, extra_context=None): context = { 'login_url': settings.LOGIN_URL 'login_url': resolve_url(settings.LOGIN_URL) } if extra_context is not None: context.update(extra_context) Loading django/shortcuts/__init__.py +32 −17 Original line number Diff line number Diff line Loading @@ -66,23 +66,7 @@ def redirect(to, *args, **kwargs): else: redirect_class = HttpResponseRedirect # If it's a model, use get_absolute_url() if hasattr(to, 'get_absolute_url'): return redirect_class(to.get_absolute_url()) # Next try a reverse URL resolution. try: return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs)) except urlresolvers.NoReverseMatch: # If this is a callable, re-raise. if callable(to): raise # If this doesn't "feel" like a URL, re-raise. if '/' not in to and '.' not in to: raise # Finally, fall back and assume it's a URL return redirect_class(to) return redirect_class(resolve_url(to, *args, **kwargs)) def _get_queryset(klass): """ Loading Loading @@ -128,3 +112,34 @@ def get_list_or_404(klass, *args, **kwargs): raise Http404('No %s matches the given query.' % queryset.model._meta.object_name) return obj_list def resolve_url(to, *args, **kwargs): """ Return a URL appropriate for the arguments passed. The arguments could be: * A model: the model's `get_absolute_url()` function will be called. * A view name, possibly with arguments: `urlresolvers.reverse()` will be used to reverse-resolve the name. * A URL, which will be returned as-is. """ # If it's a model, use get_absolute_url() if hasattr(to, 'get_absolute_url'): return to.get_absolute_url() # Next try a reverse URL resolution. try: return urlresolvers.reverse(to, args=args, kwargs=kwargs) except urlresolvers.NoReverseMatch: # If this is a callable, re-raise. if callable(to): raise # If this doesn't "feel" like a URL, re-raise. if '/' not in to and '.' not in to: raise # Finally, fall back and assume it's a URL return to docs/ref/settings.txt +13 −20 Original line number Diff line number Diff line Loading @@ -1304,25 +1304,13 @@ The URL where requests are redirected after login when the This is used by the :func:`~django.contrib.auth.decorators.login_required` decorator, for example. .. _`note on LOGIN_REDIRECT_URL setting`: .. note:: You can use :func:`~django.core.urlresolvers.reverse_lazy` to reference URLs by their name instead of providing a hardcoded value. Assuming a ``urls.py`` with an URLpattern named ``home``:: urlpatterns = patterns('', url('^welcome/$', 'test_app.views.home', name='home'), ) You can use :func:`~django.core.urlresolvers.reverse_lazy` like this:: from django.core.urlresolvers import reverse_lazy LOGIN_REDIRECT_URL = reverse_lazy('home') .. versionchanged:: 1.5 This also works fine with localized URLs using :func:`~django.conf.urls.i18n.i18n_patterns`. This setting now also accepts view function names and :ref:`named URL patterns <naming-url-patterns>` which can be used to reduce configuration duplication since you no longer have to define the URL in two places (``settings`` and URLconf). For backward compatibility reasons the default remains unchanged. .. setting:: LOGIN_URL Loading @@ -1334,8 +1322,13 @@ Default: ``'/accounts/login/'`` The URL where requests are redirected for login, especially when using the :func:`~django.contrib.auth.decorators.login_required` decorator. .. note:: See the `note on LOGIN_REDIRECT_URL setting`_ .. versionchanged:: 1.5 This setting now also accepts view function names and :ref:`named URL patterns <naming-url-patterns>` which can be used to reduce configuration duplication since you no longer have to define the URL in two places (``settings`` and URLconf). For backward compatibility reasons the default remains unchanged. .. setting:: LOGOUT_URL Loading Loading
django/contrib/auth/decorators.py +3 −3 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ from django.contrib.auth import REDIRECT_FIELD_NAME from django.core.exceptions import PermissionDenied from django.utils.decorators import available_attrs from django.utils.encoding import force_str from django.shortcuts import resolve_url def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): Loading @@ -23,11 +24,10 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE if test_func(request.user): return view_func(request, *args, **kwargs) path = request.build_absolute_uri() # urlparse chokes on lazy objects in Python 3 login_url_as_str = force_str(login_url or settings.LOGIN_URL) resolved_login_url = resolve_url(login_url or settings.LOGIN_URL) # If the login url is the same scheme and net location then just # use the path as the "next" url. login_scheme, login_netloc = urlparse(login_url_as_str)[:2] login_scheme, login_netloc = urlparse(resolved_login_url)[:2] current_scheme, current_netloc = urlparse(path)[:2] if ((not login_scheme or login_scheme == current_scheme) and (not login_netloc or login_netloc == current_netloc)): Loading
django/contrib/auth/tests/decorators.py +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ class LoginRequiredTestCase(AuthViewsTestCase): pass login_required(normal_view) def testLoginRequired(self, view_url='/login_required/', login_url=settings.LOGIN_URL): 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. Loading
django/contrib/auth/views.py +9 −9 Original line number Diff line number Diff line Loading @@ -7,9 +7,9 @@ from django.conf import settings from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect, QueryDict from django.template.response import TemplateResponse from django.utils.encoding import force_str from django.utils.http import base36_to_int from django.utils.translation import ugettext as _ from django.shortcuts import resolve_url from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.cache import never_cache from django.views.decorators.csrf import csrf_protect Loading Loading @@ -38,16 +38,16 @@ def login(request, template_name='registration/login.html', if request.method == "POST": form = authentication_form(data=request.POST) if form.is_valid(): netloc = urlparse(redirect_to)[1] # Use default setting if redirect_to is empty if not redirect_to: redirect_to = settings.LOGIN_REDIRECT_URL redirect_to = resolve_url(redirect_to) netloc = urlparse(redirect_to)[1] # Heavier security check -- don't allow redirection to a different # host. elif netloc and netloc != request.get_host(): redirect_to = settings.LOGIN_REDIRECT_URL if netloc and netloc != request.get_host(): redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL) # Okay, security checks complete. Log the user in. auth_login(request, form.get_user()) Loading Loading @@ -110,6 +110,7 @@ def logout_then_login(request, login_url=None, current_app=None, extra_context=N """ if not login_url: login_url = settings.LOGIN_URL login_url = resolve_url(login_url) return logout(request, login_url, current_app=current_app, extra_context=extra_context) def redirect_to_login(next, login_url=None, Loading @@ -117,10 +118,9 @@ def redirect_to_login(next, login_url=None, """ Redirects the user to the login page, passing the given 'next' page """ # urlparse chokes on lazy objects in Python 3 login_url_as_str = force_str(login_url or settings.LOGIN_URL) resolved_url = resolve_url(login_url or settings.LOGIN_URL) login_url_parts = list(urlparse(login_url_as_str)) login_url_parts = list(urlparse(resolved_url)) if redirect_field_name: querystring = QueryDict(login_url_parts[4], mutable=True) querystring[redirect_field_name] = next Loading Loading @@ -229,7 +229,7 @@ def password_reset_complete(request, template_name='registration/password_reset_complete.html', current_app=None, extra_context=None): context = { 'login_url': settings.LOGIN_URL 'login_url': resolve_url(settings.LOGIN_URL) } if extra_context is not None: context.update(extra_context) Loading
django/shortcuts/__init__.py +32 −17 Original line number Diff line number Diff line Loading @@ -66,23 +66,7 @@ def redirect(to, *args, **kwargs): else: redirect_class = HttpResponseRedirect # If it's a model, use get_absolute_url() if hasattr(to, 'get_absolute_url'): return redirect_class(to.get_absolute_url()) # Next try a reverse URL resolution. try: return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs)) except urlresolvers.NoReverseMatch: # If this is a callable, re-raise. if callable(to): raise # If this doesn't "feel" like a URL, re-raise. if '/' not in to and '.' not in to: raise # Finally, fall back and assume it's a URL return redirect_class(to) return redirect_class(resolve_url(to, *args, **kwargs)) def _get_queryset(klass): """ Loading Loading @@ -128,3 +112,34 @@ def get_list_or_404(klass, *args, **kwargs): raise Http404('No %s matches the given query.' % queryset.model._meta.object_name) return obj_list def resolve_url(to, *args, **kwargs): """ Return a URL appropriate for the arguments passed. The arguments could be: * A model: the model's `get_absolute_url()` function will be called. * A view name, possibly with arguments: `urlresolvers.reverse()` will be used to reverse-resolve the name. * A URL, which will be returned as-is. """ # If it's a model, use get_absolute_url() if hasattr(to, 'get_absolute_url'): return to.get_absolute_url() # Next try a reverse URL resolution. try: return urlresolvers.reverse(to, args=args, kwargs=kwargs) except urlresolvers.NoReverseMatch: # If this is a callable, re-raise. if callable(to): raise # If this doesn't "feel" like a URL, re-raise. if '/' not in to and '.' not in to: raise # Finally, fall back and assume it's a URL return to
docs/ref/settings.txt +13 −20 Original line number Diff line number Diff line Loading @@ -1304,25 +1304,13 @@ The URL where requests are redirected after login when the This is used by the :func:`~django.contrib.auth.decorators.login_required` decorator, for example. .. _`note on LOGIN_REDIRECT_URL setting`: .. note:: You can use :func:`~django.core.urlresolvers.reverse_lazy` to reference URLs by their name instead of providing a hardcoded value. Assuming a ``urls.py`` with an URLpattern named ``home``:: urlpatterns = patterns('', url('^welcome/$', 'test_app.views.home', name='home'), ) You can use :func:`~django.core.urlresolvers.reverse_lazy` like this:: from django.core.urlresolvers import reverse_lazy LOGIN_REDIRECT_URL = reverse_lazy('home') .. versionchanged:: 1.5 This also works fine with localized URLs using :func:`~django.conf.urls.i18n.i18n_patterns`. This setting now also accepts view function names and :ref:`named URL patterns <naming-url-patterns>` which can be used to reduce configuration duplication since you no longer have to define the URL in two places (``settings`` and URLconf). For backward compatibility reasons the default remains unchanged. .. setting:: LOGIN_URL Loading @@ -1334,8 +1322,13 @@ Default: ``'/accounts/login/'`` The URL where requests are redirected for login, especially when using the :func:`~django.contrib.auth.decorators.login_required` decorator. .. note:: See the `note on LOGIN_REDIRECT_URL setting`_ .. versionchanged:: 1.5 This setting now also accepts view function names and :ref:`named URL patterns <naming-url-patterns>` which can be used to reduce configuration duplication since you no longer have to define the URL in two places (``settings`` and URLconf). For backward compatibility reasons the default remains unchanged. .. setting:: LOGOUT_URL Loading