summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThinkChaos <ThinkChaos@users.noreply.github.com>2017-06-07 16:48:28 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-02-08 21:08:05 +0100
commitb99d6c9cbc8eecf480892599201eef0d14b20d71 (patch)
treea563f6643d977ba1b97f2674da5e002a700399f5
parent59841170ba1785ada10a2915b0b60efdb046ee39 (diff)
Fixed #28216 -- Added next_page/get_default_redirect_url() to LoginView.
-rw-r--r--django/contrib/auth/views.py8
-rw-r--r--docs/releases/4.0.txt6
-rw-r--r--docs/topics/auth/default.txt21
-rw-r--r--tests/auth_tests/test_views.py29
-rw-r--r--tests/auth_tests/urls.py9
5 files changed, 67 insertions, 6 deletions
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
index 529400df28..b5556aaa11 100644
--- a/django/contrib/auth/views.py
+++ b/django/contrib/auth/views.py
@@ -43,6 +43,7 @@ class LoginView(SuccessURLAllowedHostsMixin, FormView):
"""
form_class = AuthenticationForm
authentication_form = None
+ next_page = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'registration/login.html'
redirect_authenticated_user = False
@@ -63,8 +64,7 @@ class LoginView(SuccessURLAllowedHostsMixin, FormView):
return super().dispatch(request, *args, **kwargs)
def get_success_url(self):
- url = self.get_redirect_url()
- return url or resolve_url(settings.LOGIN_REDIRECT_URL)
+ return self.get_redirect_url() or self.get_default_redirect_url()
def get_redirect_url(self):
"""Return the user-originating redirect URL if it's safe."""
@@ -79,6 +79,10 @@ class LoginView(SuccessURLAllowedHostsMixin, FormView):
)
return redirect_to if url_is_safe else ''
+ def get_default_redirect_url(self):
+ """Return the default redirect URL."""
+ return resolve_url(self.next_page or settings.LOGIN_REDIRECT_URL)
+
def get_form_class(self):
return self.authentication_form or self.form_class
diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt
index 37783b906b..296967a92b 100644
--- a/docs/releases/4.0.txt
+++ b/docs/releases/4.0.txt
@@ -47,6 +47,12 @@ Minor features
* The default iteration count for the PBKDF2 password hasher is increased from
260,000 to 320,000.
+* The new
+ :attr:`LoginView.next_page <django.contrib.auth.views.LoginView.next_page>`
+ attribute and
+ :meth:`~django.contrib.auth.views.LoginView.get_default_redirect_url` method
+ allow customizing the redirect after login.
+
:mod:`django.contrib.contenttypes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt
index 05ccc5eed6..82cf58c128 100644
--- a/docs/topics/auth/default.txt
+++ b/docs/topics/auth/default.txt
@@ -996,17 +996,26 @@ implementation details see :ref:`using-the-views`.
See :doc:`the URL documentation </topics/http/urls>` for details on using
named URL patterns.
- **Attributes:**
+ **Methods and Attributes**
.. attribute:: template_name
The name of a template to display for the view used to log the user in.
Defaults to :file:`registration/login.html`.
+ .. attribute:: next_page
+
+ .. versionadded:: 4.0
+
+ The URL to redirect to after login. Defaults to
+ :setting:`LOGIN_REDIRECT_URL`.
+
.. attribute:: redirect_field_name
The name of a ``GET`` field containing the URL to redirect to after
- login. Defaults to ``next``.
+ login. Defaults to ``next``. Overrides the
+ :meth:`get_default_redirect_url` URL if the given ``GET`` parameter is
+ passed.
.. attribute:: authentication_form
@@ -1043,6 +1052,14 @@ implementation details see :ref:`using-the-views`.
<django.http.HttpRequest.get_host>`, that are safe for redirecting
after login. Defaults to an empty :class:`set`.
+ .. method:: get_default_redirect_url()
+
+ .. versionadded:: 4.0
+
+ Returns the URL to redirect to after login. The default implementation
+ resolves and returns :attr:`next_page` if set, or
+ :setting:`LOGIN_REDIRECT_URL` otherwise.
+
Here's what ``LoginView`` does:
* If called via ``GET``, it displays a login form that POSTs to the
diff --git a/tests/auth_tests/test_views.py b/tests/auth_tests/test_views.py
index e57d661772..0ec3a134c2 100644
--- a/tests/auth_tests/test_views.py
+++ b/tests/auth_tests/test_views.py
@@ -52,8 +52,8 @@ class AuthViewsTestCase(TestCase):
cls.u1 = User.objects.create_user(username='testclient', password='password', email='testclient@example.com')
cls.u3 = User.objects.create_user(username='staff', password='password', email='staffmember@example.com')
- def login(self, username='testclient', password='password'):
- response = self.client.post('/login/', {
+ def login(self, username='testclient', password='password', url='/login/'):
+ response = self.client.post(url, {
'username': username,
'password': password,
})
@@ -726,6 +726,31 @@ class LoginTest(AuthViewsTestCase):
self.login()
self.assertNotEqual(original_session_key, self.client.session.session_key)
+ def test_login_get_default_redirect_url(self):
+ response = self.login(url='/login/get_default_redirect_url/')
+ self.assertRedirects(response, '/custom/', fetch_redirect_response=False)
+
+ def test_login_next_page(self):
+ response = self.login(url='/login/next_page/')
+ self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False)
+
+ def test_login_named_next_page_named(self):
+ response = self.login(url='/login/next_page/named/')
+ self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False)
+
+ @override_settings(LOGIN_REDIRECT_URL='/custom/')
+ def test_login_next_page_overrides_login_redirect_url_setting(self):
+ response = self.login(url='/login/next_page/')
+ self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False)
+
+ def test_login_redirect_url_overrides_next_page(self):
+ response = self.login(url='/login/next_page/?next=/test/')
+ self.assertRedirects(response, '/test/', fetch_redirect_response=False)
+
+ def test_login_redirect_url_overrides_get_default_redirect_url(self):
+ response = self.login(url='/login/get_default_redirect_url/?next=/test/')
+ self.assertRedirects(response, '/test/', fetch_redirect_response=False)
+
class LoginURLSettings(AuthViewsTestCase):
"""Tests for settings.LOGIN_URL."""
diff --git a/tests/auth_tests/urls.py b/tests/auth_tests/urls.py
index e225ab9362..044f0da037 100644
--- a/tests/auth_tests/urls.py
+++ b/tests/auth_tests/urls.py
@@ -3,6 +3,7 @@ from django.contrib.auth import views
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.urls import urlpatterns as auth_urlpatterns
+from django.contrib.auth.views import LoginView
from django.contrib.messages.api import info
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
@@ -78,6 +79,11 @@ def login_and_permission_required_exception(request):
pass
+class CustomDefaultRedirectURLLoginView(LoginView):
+ def get_default_redirect_url(self):
+ return '/custom/'
+
+
# special urls for auth test cases
urlpatterns = auth_urlpatterns + [
path('logout/custom_query/', views.LogoutView.as_view(redirect_field_name='follow')),
@@ -149,6 +155,9 @@ urlpatterns = auth_urlpatterns + [
views.LoginView.as_view(redirect_authenticated_user=True)),
path('login/allowed_hosts/',
views.LoginView.as_view(success_url_allowed_hosts={'otherserver'})),
+ path('login/get_default_redirect_url/', CustomDefaultRedirectURLLoginView.as_view()),
+ path('login/next_page/', views.LoginView.as_view(next_page='/somewhere/')),
+ path('login/next_page/named/', views.LoginView.as_view(next_page='password_reset')),
path('permission_required_redirect/', permission_required_redirect),
path('permission_required_exception/', permission_required_exception),