Refs #17209 -- Added LoginView and LogoutView class-based views

Thanks Tim Graham for the review.
This commit is contained in:
Claude Paroz 2016-05-15 17:28:00 +02:00
parent 742ea51413
commit 78963495d0
16 changed files with 226 additions and 157 deletions

View File

@ -327,7 +327,7 @@ class AdminSite(object):
This should *not* assume the user is already logged in. This should *not* assume the user is already logged in.
""" """
from django.contrib.auth.views import logout from django.contrib.auth.views import LogoutView
defaults = { defaults = {
'extra_context': dict( 'extra_context': dict(
self.each_context(request), self.each_context(request),
@ -340,7 +340,7 @@ class AdminSite(object):
if self.logout_template is not None: if self.logout_template is not None:
defaults['template_name'] = self.logout_template defaults['template_name'] = self.logout_template
request.current_app = self.name request.current_app = self.name
return logout(request, **defaults) return LogoutView.as_view(**defaults)(request)
@never_cache @never_cache
def login(self, request, extra_context=None): def login(self, request, extra_context=None):
@ -352,7 +352,7 @@ class AdminSite(object):
index_path = reverse('admin:index', current_app=self.name) index_path = reverse('admin:index', current_app=self.name)
return HttpResponseRedirect(index_path) return HttpResponseRedirect(index_path)
from django.contrib.auth.views import login from django.contrib.auth.views import LoginView
# Since this module gets imported in the application's root package, # Since this module gets imported in the application's root package,
# it cannot import models from other applications at the module level, # it cannot import models from other applications at the module level,
# and django.contrib.admin.forms eventually imports User. # and django.contrib.admin.forms eventually imports User.
@ -374,7 +374,7 @@ class AdminSite(object):
'template_name': self.login_template or 'admin/login.html', 'template_name': self.login_template or 'admin/login.html',
} }
request.current_app = self.name request.current_app = self.name
return login(request, **defaults) return LoginView.as_view(**defaults)(request)
def _build_app_dict(self, request, label=None): def _build_app_dict(self, request, label=None):
""" """

View File

@ -7,8 +7,8 @@ from django.conf.urls import url
from django.contrib.auth import views from django.contrib.auth import views
urlpatterns = [ urlpatterns = [
url(r'^login/$', views.login, name='login'), url(r'^login/$', views.LoginView.as_view(), name='login'),
url(r'^logout/$', views.logout, name='logout'), url(r'^logout/$', views.LogoutView.as_view(), name='logout'),
url(r'^password_change/$', views.password_change, name='password_change'), url(r'^password_change/$', views.password_change, name='password_change'),
url(r'^password_change/done/$', views.password_change_done, name='password_change_done'), url(r'^password_change/done/$', views.password_change_done, name='password_change_done'),
url(r'^password_reset/$', views.password_reset, name='password_reset'), url(r'^password_reset/$', views.password_reset, name='password_reset'),

View File

@ -17,7 +17,10 @@ from django.http import HttpResponseRedirect, QueryDict
from django.shortcuts import resolve_url from django.shortcuts import resolve_url
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import reverse from django.urls import reverse
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.decorators import method_decorator
from django.utils.deprecation import (
RemovedInDjango20Warning, RemovedInDjango21Warning,
)
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.http import is_safe_url, urlsafe_base64_decode from django.utils.http import is_safe_url, urlsafe_base64_decode
from django.utils.six.moves.urllib.parse import urlparse, urlunparse from django.utils.six.moves.urllib.parse import urlparse, urlunparse
@ -25,6 +28,8 @@ from django.utils.translation import ugettext as _
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
def deprecate_current_app(func): def deprecate_current_app(func):
@ -48,94 +53,128 @@ def deprecate_current_app(func):
return inner return inner
def _get_login_redirect_url(request, redirect_to): class LoginView(FormView):
# Ensure the user-originating redirection URL is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
return resolve_url(settings.LOGIN_REDIRECT_URL)
return redirect_to
@deprecate_current_app
@sensitive_post_parameters()
@csrf_protect
@never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
extra_context=None, redirect_authenticated_user=False):
""" """
Displays the login form and handles the login action. Displays the login form and handles the login action.
""" """
redirect_to = request.POST.get(redirect_field_name, request.GET.get(redirect_field_name, '')) form_class = AuthenticationForm
authentication_form = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'registration/login.html'
redirect_authenticated_user = False
extra_context = None
if redirect_authenticated_user and request.user.is_authenticated: @method_decorator(sensitive_post_parameters())
redirect_to = _get_login_redirect_url(request, redirect_to) @method_decorator(csrf_protect)
if redirect_to == request.path: @method_decorator(never_cache)
raise ValueError( def dispatch(self, request, *args, **kwargs):
"Redirection loop for authenticated user detected. Check that " if self.redirect_authenticated_user and self.request.user.is_authenticated:
"your LOGIN_REDIRECT_URL doesn't point to a login page." redirect_to = self.get_success_url()
) if redirect_to == self.request.path:
return HttpResponseRedirect(redirect_to) raise ValueError(
elif request.method == "POST": "Redirection loop for authenticated user detected. Check that "
form = authentication_form(request, data=request.POST) "your LOGIN_REDIRECT_URL doesn't point to a login page."
if form.is_valid(): )
auth_login(request, form.get_user()) return HttpResponseRedirect(redirect_to)
return HttpResponseRedirect(_get_login_redirect_url(request, redirect_to)) return super(LoginView, self).dispatch(request, *args, **kwargs)
else:
form = authentication_form(request)
current_site = get_current_site(request) def get_success_url(self):
"""Ensure the user-originating redirection URL is safe."""
redirect_to = self.request.POST.get(
self.redirect_field_name,
self.request.GET.get(self.redirect_field_name, '')
)
if not is_safe_url(url=redirect_to, host=self.request.get_host()):
return resolve_url(settings.LOGIN_REDIRECT_URL)
return redirect_to
context = { def get_form_class(self):
'form': form, return self.authentication_form or self.form_class
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context) def form_valid(self, form):
"""Security check complete. Log the user in."""
auth_login(self.request, form.get_user())
return HttpResponseRedirect(self.get_success_url())
def get_context_data(self, **kwargs):
context = super(LoginView, self).get_context_data(**kwargs)
current_site = get_current_site(self.request)
context.update({
self.redirect_field_name: self.get_success_url(),
'site': current_site,
'site_name': current_site.name,
})
if self.extra_context is not None:
context.update(self.extra_context)
return context
@deprecate_current_app @deprecate_current_app
@never_cache def login(request, *args, **kwargs):
def logout(request, next_page=None, warnings.warn(
template_name='registration/logged_out.html', 'The login() view is superseded by the class-based LoginView().',
redirect_field_name=REDIRECT_FIELD_NAME, RemovedInDjango21Warning, stacklevel=2
extra_context=None): )
return LoginView.as_view(**kwargs)(request, *args, **kwargs)
class LogoutView(TemplateView):
""" """
Logs out the user and displays 'You are logged out' message. Logs out the user and displays 'You are logged out' message.
""" """
auth_logout(request) next_page = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'registration/logged_out.html'
extra_context = None
if next_page is not None: @method_decorator(never_cache)
next_page = resolve_url(next_page) def dispatch(self, request, *args, **kwargs):
elif settings.LOGOUT_REDIRECT_URL: auth_logout(request)
next_page = resolve_url(settings.LOGOUT_REDIRECT_URL) next_page = self.get_next_page()
if next_page:
# Redirect to this page until the session has been cleared.
return HttpResponseRedirect(next_page)
return super(LogoutView, self).dispatch(request, *args, **kwargs)
if (redirect_field_name in request.POST or def get_next_page(self):
redirect_field_name in request.GET): if self.next_page is not None:
next_page = request.POST.get(redirect_field_name, next_page = resolve_url(self.next_page)
request.GET.get(redirect_field_name)) elif settings.LOGOUT_REDIRECT_URL:
# Security check -- don't allow redirection to a different host. next_page = resolve_url(settings.LOGOUT_REDIRECT_URL)
if not is_safe_url(url=next_page, host=request.get_host()): else:
next_page = request.path next_page = self.next_page
if next_page: if (self.redirect_field_name in self.request.POST or
# Redirect to this page until the session has been cleared. self.redirect_field_name in self.request.GET):
return HttpResponseRedirect(next_page) next_page = self.request.POST.get(
self.redirect_field_name,
self.request.GET.get(self.redirect_field_name)
)
# Security check -- don't allow redirection to a different host.
if not is_safe_url(url=next_page, host=self.request.get_host()):
next_page = self.request.path
return next_page
current_site = get_current_site(request) def get_context_data(self, **kwargs):
context = { context = super(LogoutView, self).get_context_data(**kwargs)
'site': current_site, current_site = get_current_site(self.request)
'site_name': current_site.name, context.update({
'title': _('Logged out') 'site': current_site,
} 'site_name': current_site.name,
if extra_context is not None: 'title': _('Logged out'),
context.update(extra_context) })
if self.extra_context is not None:
context.update(self.extra_context)
return context
return TemplateResponse(request, template_name, context)
@deprecate_current_app
def logout(request, *args, **kwargs):
warnings.warn(
'The logout() view is superseded by the class-based LogoutView().',
RemovedInDjango21Warning, stacklevel=2
)
return LogoutView.as_view(**kwargs)(request, *args, **kwargs)
@deprecate_current_app @deprecate_current_app

View File

@ -15,6 +15,8 @@ about each item can often be found in the release notes of two versions prior.
See the :ref:`Django 1.11 release notes<deprecated-features-1.11>` for more See the :ref:`Django 1.11 release notes<deprecated-features-1.11>` for more
details on these changes. details on these changes.
* ``contrib.auth.views.login()`` and ``logout()`` will be removed.
.. _deprecation-removed-in-2.0: .. _deprecation-removed-in-2.0:
2.0 2.0

View File

@ -93,7 +93,7 @@ Fields
if you want to allow inactive users to login. In this case, you'll also if you want to allow inactive users to login. In this case, you'll also
want to customize the want to customize the
:class:`~django.contrib.auth.forms.AuthenticationForm` used by the :class:`~django.contrib.auth.forms.AuthenticationForm` used by the
:func:`~django.contrib.auth.views.login` view as it rejects inactive :class:`~django.contrib.auth.views.LoginView` as it rejects inactive
users. Be aware that the permission-checking methods such as users. Be aware that the permission-checking methods such as
:meth:`~django.contrib.auth.models.User.has_perm` and the :meth:`~django.contrib.auth.models.User.has_perm` and the
authentication in the Django admin all return ``False`` for inactive authentication in the Django admin all return ``False`` for inactive
@ -582,7 +582,7 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
When using this backend, you'll likely want to customize the When using this backend, you'll likely want to customize the
:class:`~django.contrib.auth.forms.AuthenticationForm` used by the :class:`~django.contrib.auth.forms.AuthenticationForm` used by the
:func:`~django.contrib.auth.views.login` view by overriding the :class:`~django.contrib.auth.views.LoginView` by overriding the
:meth:`~django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed` :meth:`~django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed`
method as it rejects inactive users. method as it rejects inactive users.

View File

@ -436,8 +436,8 @@ Here's how Django uses the sites framework:
the current :class:`~django.contrib.sites.models.Site` object if you don't the current :class:`~django.contrib.sites.models.Site` object if you don't
specify a fully-qualified domain. specify a fully-qualified domain.
* In the :mod:`authentication framework <django.contrib.auth>`, the * In the :mod:`authentication framework <django.contrib.auth>`,
:func:`django.contrib.auth.views.login` view passes the current :class:`django.contrib.auth.views.LoginView` passes the current
:class:`~django.contrib.sites.models.Site` name to the template as :class:`~django.contrib.sites.models.Site` name to the template as
``{{ site_name }}``. ``{{ site_name }}``.

View File

@ -2736,8 +2736,8 @@ the URL in two places (``settings`` and URLconf).
Default: ``None`` Default: ``None``
The URL where requests are redirected after a user logs out using the The URL where requests are redirected after a user logs out using
:func:`~django.contrib.auth.views.logout` view (if the view doesn't get a :class:`~django.contrib.auth.views.LogoutView` (if the view doesn't get a
``next_page`` argument). ``next_page`` argument).
If ``None``, no redirect will be performed and the logout view will be If ``None``, no redirect will be performed and the logout view will be

View File

@ -66,6 +66,10 @@ Minor features
* The default iteration count for the PBKDF2 password hasher is increased by * The default iteration count for the PBKDF2 password hasher is increased by
20%. 20%.
* The :class:`~django.contrib.auth.views.LoginView` and
:class:`~django.contrib.auth.views.LogoutView` class-based views supersede the
deprecated ``login()`` and ``logout()`` function-based views.
:mod:`django.contrib.contenttypes` :mod:`django.contrib.contenttypes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -297,4 +301,7 @@ Features deprecated in 1.11
Miscellaneous Miscellaneous
------------- -------------
* ... * ``contrib.auth``s ``login()`` and ``logout()`` function-based views are
deprecated in favor of new class-based views
:class:`~django.contrib.auth.views.LoginView` and
:class:`~django.contrib.auth.views.LogoutView`.

View File

@ -503,7 +503,7 @@ The ``login_required`` decorator
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
url(r'^accounts/login/$', auth_views.login), url(r'^accounts/login/$', auth_views.Login.as_view()),
The :setting:`settings.LOGIN_URL <LOGIN_URL>` also accepts view function The :setting:`settings.LOGIN_URL <LOGIN_URL>` also accepts view function
names and :ref:`named URL patterns <naming-url-patterns>`. This allows you names and :ref:`named URL patterns <naming-url-patterns>`. This allows you
@ -957,12 +957,37 @@ implementation details see :ref:`using-the-views`.
.. function:: login(request, template_name=`registration/login.html`, redirect_field_name='next', authentication_form=AuthenticationForm, current_app=None, extra_context=None, redirect_authenticated_user=False) .. function:: login(request, template_name=`registration/login.html`, redirect_field_name='next', authentication_form=AuthenticationForm, current_app=None, extra_context=None, redirect_authenticated_user=False)
.. deprecated:: 1.11
The ``login`` function-based view should be replaced by the class-based
:class:`LoginView`.
The optional arguments of this view are similar to the class-based
``LoginView`` optional attributes. In addition, it has:
* ``current_app``: A hint indicating which application contains the
current view. See the :ref:`namespaced URL resolution strategy
<topics-http-reversing-url-namespaces>` for more information.
.. deprecated:: 1.9
The ``current_app`` attribute is deprecated and will be removed in
Django 2.0. Callers should set ``request.current_app`` instead.
.. versionadded:: 1.10
The ``redirect_authenticated_user`` parameter was added.
.. class:: LoginView
.. versionadded:: 1.11
**URL name:** ``login`` **URL name:** ``login``
See :doc:`the URL documentation </topics/http/urls>` for details on using See :doc:`the URL documentation </topics/http/urls>` for details on using
named URL patterns. named URL patterns.
**Optional arguments:** **Attributes:**
* ``template_name``: The name of a template to display for the view used to * ``template_name``: The name of a template to display for the view used to
log the user in. Defaults to :file:`registration/login.html`. log the user in. Defaults to :file:`registration/login.html`.
@ -974,10 +999,6 @@ implementation details see :ref:`using-the-views`.
use for authentication. Defaults to use for authentication. Defaults to
:class:`~django.contrib.auth.forms.AuthenticationForm`. :class:`~django.contrib.auth.forms.AuthenticationForm`.
* ``current_app``: A hint indicating which application contains the current
view. See the :ref:`namespaced URL resolution strategy
<topics-http-reversing-url-namespaces>` for more information.
* ``extra_context``: A dictionary of context data that will be added to the * ``extra_context``: A dictionary of context data that will be added to the
default context data passed to the template. default context data passed to the template.
@ -985,16 +1006,7 @@ implementation details see :ref:`using-the-views`.
authenticated users accessing the login page will be redirected as if authenticated users accessing the login page will be redirected as if
they had just successfully logged in. Defaults to ``False``. they had just successfully logged in. Defaults to ``False``.
.. deprecated:: 1.9 Here's what ``LoginView`` does:
The ``current_app`` parameter is deprecated and will be removed in
Django 2.0. Callers should set ``request.current_app`` instead.
.. versionadded:: 1.10
The ``redirect_authenticated_user`` parameter was added.
Here's what ``django.contrib.auth.views.login`` does:
* If called via ``GET``, it displays a login form that POSTs to the * If called via ``GET``, it displays a login form that POSTs to the
same URL. More on this in a bit. same URL. More on this in a bit.
@ -1030,14 +1042,14 @@ implementation details see :ref:`using-the-views`.
If you'd prefer not to call the template :file:`registration/login.html`, If you'd prefer not to call the template :file:`registration/login.html`,
you can pass the ``template_name`` parameter via the extra arguments to you can pass the ``template_name`` parameter via the extra arguments to
the view in your URLconf. For example, this URLconf line would use the ``as_view`` method in your URLconf. For example, this URLconf line would
:file:`myapp/login.html` instead:: use :file:`myapp/login.html` instead::
url(r'^accounts/login/$', auth_views.login, {'template_name': 'myapp/login.html'}), url(r'^accounts/login/$', auth_views.LoginView.as_view(template_name='myapp/login.html')),
You can also specify the name of the ``GET`` field which contains the URL You can also specify the name of the ``GET`` field which contains the URL
to redirect to after login by passing ``redirect_field_name`` to the view. to redirect to after login using ``redirect_field_name``. By default, the
By default, the field is called ``next``. field is called ``next``.
Here's a sample :file:`registration/login.html` template you can use as a Here's a sample :file:`registration/login.html` template you can use as a
starting point. It assumes you have a :file:`base.html` template that starting point. It assumes you have a :file:`base.html` template that
@ -1084,49 +1096,55 @@ implementation details see :ref:`using-the-views`.
{% endblock %} {% endblock %}
If you have customized authentication (see If you have customized authentication (see :doc:`Customizing Authentication
:doc:`Customizing Authentication </topics/auth/customizing>`) you can pass </topics/auth/customizing>`) you can use a custom authentication form by
a custom authentication form to the login view via the setting the ``authentication_form`` attribute. This form must accept a
``authentication_form`` parameter. This form must accept a ``request`` ``request`` keyword argument in its ``__init__()`` method and provide a
keyword argument in its ``__init__`` method, and provide a ``get_user()`` ``get_user()`` method which returns the authenticated user object (this
method which returns the authenticated user object (this method is only method is only ever called after successful form validation).
ever called after successful form validation).
.. _forms documentation: ../forms/
.. _site framework docs: ../sites/
.. function:: logout(request, next_page=None, template_name='registration/logged_out.html', redirect_field_name='next', current_app=None, extra_context=None) .. function:: logout(request, next_page=None, template_name='registration/logged_out.html', redirect_field_name='next', current_app=None, extra_context=None)
.. deprecated:: 1.11
The ``logout`` function-based view should be replaced by the
class-based :class:`LogoutView`.
The optional arguments of this view are similar to the class-based
``LogoutView`` optional attributes. In addition, it has:
* ``current_app``: A hint indicating which application contains the
current view. See the :ref:`namespaced URL resolution strategy
<topics-http-reversing-url-namespaces>` for more information.
.. deprecated:: 1.9
The ``current_app`` attribute is deprecated and will be removed in
Django 2.0. Callers should set ``request.current_app`` instead.
.. class:: LogoutView
.. versionadded:: 1.11
Logs a user out. Logs a user out.
**URL name:** ``logout`` **URL name:** ``logout``
**Optional arguments:** **Attributes:**
* ``next_page``: The URL to redirect to after logout. Defaults to * ``next_page``: The URL to redirect to after logout. Defaults to
:setting:`settings.LOGOUT_REDIRECT_URL <LOGOUT_REDIRECT_URL>` if not :setting:`settings.LOGOUT_REDIRECT_URL <LOGOUT_REDIRECT_URL>`.
supplied.
* ``template_name``: The full name of a template to display after * ``template_name``: The full name of a template to display after
logging the user out. Defaults to logging the user out. Defaults to :file:`registration/logged_out.html`.
:file:`registration/logged_out.html` if no argument is supplied.
* ``redirect_field_name``: The name of a ``GET`` field containing the * ``redirect_field_name``: The name of a ``GET`` field containing the
URL to redirect to after log out. Defaults to ``next``. Overrides the URL to redirect to after log out. Defaults to ``next``. Overrides the
``next_page`` URL if the given ``GET`` parameter is passed. ``next_page`` URL if the given ``GET`` parameter is passed.
* ``current_app``: A hint indicating which application contains the current
view. See the :ref:`namespaced URL resolution strategy
<topics-http-reversing-url-namespaces>` for more information.
* ``extra_context``: A dictionary of context data that will be added to the * ``extra_context``: A dictionary of context data that will be added to the
default context data passed to the template. default context data passed to the template.
.. deprecated:: 1.9
The ``current_app`` parameter is deprecated and will be removed in
Django 2.0. Callers should set ``request.current_app`` instead.
**Template context:** **Template context:**
* ``title``: The string "Logged out", localized. * ``title``: The string "Logged out", localized.

View File

@ -15,7 +15,7 @@ from django.contrib.auth.forms import (
AuthenticationForm, PasswordChangeForm, SetPasswordForm, AuthenticationForm, PasswordChangeForm, SetPasswordForm,
) )
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.views import login as login_view, redirect_to_login from django.contrib.auth.views import LoginView, redirect_to_login
from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.sites.requests import RequestSite from django.contrib.sites.requests import RequestSite
from django.core import mail from django.core import mail
@ -553,10 +553,10 @@ class LoginTest(AuthViewsTestCase):
# Do a GET to establish a CSRF token # Do a GET to establish a CSRF token
# TestClient isn't used here as we're testing middleware, essentially. # TestClient isn't used here as we're testing middleware, essentially.
req = HttpRequest() req = HttpRequest()
CsrfViewMiddleware().process_view(req, login_view, (), {}) CsrfViewMiddleware().process_view(req, LoginView.as_view(), (), {})
# get_token() triggers CSRF token inclusion in the response # get_token() triggers CSRF token inclusion in the response
get_token(req) get_token(req)
resp = login_view(req) resp = LoginView.as_view()(req)
resp2 = CsrfViewMiddleware().process_response(req, resp) resp2 = CsrfViewMiddleware().process_response(req, resp)
csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, None) csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, None)
token1 = csrf_cookie.coded_value token1 = csrf_cookie.coded_value
@ -569,10 +569,10 @@ class LoginTest(AuthViewsTestCase):
# Use POST request to log in # Use POST request to log in
SessionMiddleware().process_request(req) SessionMiddleware().process_request(req)
CsrfViewMiddleware().process_view(req, login_view, (), {}) CsrfViewMiddleware().process_view(req, LoginView.as_view(), (), {})
req.META["SERVER_NAME"] = "testserver" # Required to have redirect work in login view req.META["SERVER_NAME"] = "testserver" # Required to have redirect work in login view
req.META["SERVER_PORT"] = 80 req.META["SERVER_PORT"] = 80
resp = login_view(req) resp = LoginView.as_view()(req)
resp2 = CsrfViewMiddleware().process_response(req, resp) resp2 = CsrfViewMiddleware().process_response(req, resp)
csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, None) csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, None)
token2 = csrf_cookie.coded_value token2 = csrf_cookie.coded_value

View File

@ -61,14 +61,11 @@ def userpage(request):
pass pass
def custom_request_auth_login(request):
return views.login(request, authentication_form=CustomRequestAuthenticationForm)
# special urls for auth test cases # special urls for auth test cases
urlpatterns = auth_urlpatterns + [ urlpatterns = auth_urlpatterns + [
url(r'^logout/custom_query/$', views.logout, dict(redirect_field_name='follow')), url(r'^logout/custom_query/$', views.LogoutView.as_view(redirect_field_name='follow')),
url(r'^logout/next_page/$', views.logout, dict(next_page='/somewhere/')), url(r'^logout/next_page/$', views.LogoutView.as_view(next_page='/somewhere/')),
url(r'^logout/next_page/named/$', views.logout, dict(next_page='password_reset')), url(r'^logout/next_page/named/$', views.LogoutView.as_view(next_page='password_reset')),
url(r'^remote_user/$', remote_user_auth_view), url(r'^remote_user/$', remote_user_auth_view),
url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')), url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')),
url(r'^password_reset_extra_email_context/$', views.password_reset, url(r'^password_reset_extra_email_context/$', views.password_reset,
@ -94,10 +91,12 @@ urlpatterns = auth_urlpatterns + [
url(r'^auth_processor_perms/$', auth_processor_perms), url(r'^auth_processor_perms/$', auth_processor_perms),
url(r'^auth_processor_perm_in_perms/$', auth_processor_perm_in_perms), url(r'^auth_processor_perm_in_perms/$', auth_processor_perm_in_perms),
url(r'^auth_processor_messages/$', auth_processor_messages), url(r'^auth_processor_messages/$', auth_processor_messages),
url(r'^custom_request_auth_login/$', custom_request_auth_login), url(r'^custom_request_auth_login/$',
views.LoginView.as_view(authentication_form=CustomRequestAuthenticationForm)),
url(r'^userpage/(.+)/$', userpage, name="userpage"), url(r'^userpage/(.+)/$', userpage, name="userpage"),
url(r'^login/redirect_authenticated_user_default/$', views.login), url(r'^login/redirect_authenticated_user_default/$', views.LoginView.as_view()),
url(r'^login/redirect_authenticated_user/$', views.login, dict(redirect_authenticated_user=True)), url(r'^login/redirect_authenticated_user/$',
views.LoginView.as_view(redirect_authenticated_user=True)),
# This line is only required to render the password reset with is_admin=True # This line is only required to render the password reset with is_admin=True
url(r'^admin/', admin.site.urls), url(r'^admin/', admin.site.urls),

View File

@ -292,5 +292,5 @@ urlpatterns = [
views.BookSigningDetail.as_view()), views.BookSigningDetail.as_view()),
# Useful for testing redirects # Useful for testing redirects
url(r'^accounts/login/$', auth_views.login) url(r'^accounts/login/$', auth_views.LoginView.as_view())
] ]

View File

@ -1,12 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth.views import logout
from django.shortcuts import resolve_url from django.shortcuts import resolve_url
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
from django.urls import NoReverseMatch, reverse_lazy from django.urls import NoReverseMatch, reverse_lazy
from django.utils import six from django.utils import six
from .models import UnimportantThing from .models import UnimportantThing
from .urls import some_view
@override_settings(ROOT_URLCONF='resolve_url.urls') @override_settings(ROOT_URLCONF='resolve_url.urls')
@ -53,25 +53,25 @@ class ResolveUrlTests(SimpleTestCase):
Tests that passing a view function to ``resolve_url`` will result in Tests that passing a view function to ``resolve_url`` will result in
the URL path mapping to that view name. the URL path mapping to that view name.
""" """
resolved_url = resolve_url(logout) resolved_url = resolve_url(some_view)
self.assertEqual('/accounts/logout/', resolved_url) self.assertEqual('/some-url/', resolved_url)
def test_lazy_reverse(self): def test_lazy_reverse(self):
""" """
Tests that passing the result of reverse_lazy is resolved to a real URL Tests that passing the result of reverse_lazy is resolved to a real URL
string. string.
""" """
resolved_url = resolve_url(reverse_lazy('logout')) resolved_url = resolve_url(reverse_lazy('some-view'))
self.assertIsInstance(resolved_url, six.text_type) self.assertIsInstance(resolved_url, six.text_type)
self.assertEqual('/accounts/logout/', resolved_url) self.assertEqual('/some-url/', resolved_url)
def test_valid_view_name(self): def test_valid_view_name(self):
""" """
Tests that passing a view name to ``resolve_url`` will result in the Tests that passing a view name to ``resolve_url`` will result in the
URL path mapping to that view. URL path mapping to that view.
""" """
resolved_url = resolve_url('logout') resolved_url = resolve_url('some-view')
self.assertEqual('/accounts/logout/', resolved_url) self.assertEqual('/some-url/', resolved_url)
def test_domain(self): def test_domain(self):
""" """

View File

@ -1,6 +1,10 @@
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth import views
def some_view(request):
pass
urlpatterns = [ urlpatterns = [
url(r'^accounts/logout/$', views.logout, name='logout'), url(r'^some-url/$', some_view, name='some-view'),
] ]

View File

@ -36,6 +36,6 @@ urlpatterns = [
url(r'^accounts/$', RedirectView.as_view(url='login/')), url(r'^accounts/$', RedirectView.as_view(url='login/')),
url(r'^accounts/no_trailing_slash$', RedirectView.as_view(url='login/')), url(r'^accounts/no_trailing_slash$', RedirectView.as_view(url='login/')),
url(r'^accounts/login/$', auth_views.login, {'template_name': 'login.html'}), url(r'^accounts/login/$', auth_views.LoginView.as_view(template_name='login.html')),
url(r'^accounts/logout/$', auth_views.logout), url(r'^accounts/logout/$', auth_views.LogoutView.as_view()),
] ]

View File

@ -28,8 +28,8 @@ numeric_days_info_dict = dict(date_based_info_dict, day_format='%d')
date_based_datefield_info_dict = dict(date_based_info_dict, queryset=DateArticle.objects.all()) date_based_datefield_info_dict = dict(date_based_info_dict, queryset=DateArticle.objects.all())
urlpatterns = [ urlpatterns = [
url(r'^accounts/login/$', auth_views.login, {'template_name': 'login.html'}), url(r'^accounts/login/$', auth_views.LoginView.as_view(template_name='login.html')),
url(r'^accounts/logout/$', auth_views.logout), url(r'^accounts/logout/$', auth_views.LogoutView.as_view()),
# Special URLs for particular regression cases. # Special URLs for particular regression cases.
url('^中文/target/$', views.index_page), url('^中文/target/$', views.index_page),