@@ -425,8 +425,8 @@ login page::
425425
426426.. currentmodule:: django.contrib.auth.decorators
427427
428- The login_required decorator
429- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
428+ The `` login_required`` decorator
429+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
430430
431431.. function:: login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None])
432432
@@ -500,6 +500,43 @@ The login_required decorator
500500 :func:`django.contrib.admin.views.decorators.staff_member_required`
501501 decorator a useful alternative to ``login_required()``.
502502
503+ .. currentmodule:: django.contrib.auth.mixins
504+
505+ The ``LoginRequired`` mixin
506+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
507+
508+ When using :doc:`class-based views </topics/class-based-views/index>`, you can
509+ achieve the same behavior as with ``login_required`` by using the
510+ ``LoginRequiredMixin``. This mixin should be at the leftmost position in the
511+ inheritance list.
512+
513+ .. class:: LoginRequiredMixin
514+
515+ .. versionadded:: 1.9
516+
517+ If a view is using this mixin, all requests by non-authenticated users will
518+ be redirected to the login page or shown an HTTP 403 Forbidden error,
519+ depending on the
520+ :attr:`~django.contrib.auth.mixins.AccessMixin.raise_exception` parameter.
521+
522+ You can set any of the parameters of
523+ :class:`~django.contrib.auth.mixins.AccessMixin` to customize the handling
524+ of unauthorized users::
525+
526+
527+ from django.contrib.auth.mixins import LoginRequiredMixin
528+
529+ class MyView(LoginRequiredMixin, View):
530+ login_url = '/login/'
531+ redirect_field_name = 'redirect_to'
532+
533+ .. note::
534+
535+ Just as the ``login_required`` decorator, this mixin does NOT check the
536+ ``is_active`` flag on a user.
537+
538+ .. currentmodule:: django.contrib.auth.decorators
539+
503540Limiting access to logged-in users that pass a test
504541~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
505542
@@ -560,8 +597,50 @@ redirects to the login page::
560597 def my_view(request):
561598 ...
562599
563- The permission_required decorator
564- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
600+ .. currentmodule:: django.contrib.auth.mixins
601+
602+ .. class:: UserPassesTestMixin
603+
604+ .. versionadded:: 1.9
605+
606+ When using :doc:`class-based views </topics/class-based-views/index>`, you
607+ can use the ``UserPassesTestMixin`` to do this.
608+
609+ You have to override the ``test_func()`` method of the class to provide
610+ the test that is performed. Furthermore, you can set any of the parameters
611+ of :class:`~django.contrib.auth.mixins.AccessMixin` to customize the
612+ handling of unauthorized users::
613+
614+ from django.contrib.auth.mixins import UserPassesTestMixin
615+
616+ class MyView(UserPassesTestMixin, View):
617+
618+ def test_func(self):
619+ return self.request.user.email.endswith('@example.com')
620+
621+ .. admonition: Stacking UserPassesTestMixin
622+
623+ Due to the way ``UserPassesTestMixin`` is implemented, you cannot stack
624+ them in your inheritance list. The following does NOT work::
625+
626+ class TestMixin1(UserPassesTestMixin):
627+ def test_func(self):
628+ return self.request.user.email.endswith('@example.com')
629+
630+ class TestMixin2(UserPassesTestMixin):
631+ def test_func(self):
632+ return self.request.user.username.startswith('django')
633+
634+ class MyView(TestMixin1, TestMixin2, View):
635+ ...
636+
637+ If ``TestMixin1`` would call ``super()`` and take that result into
638+ account, ``TestMixin1`` wouldn't work standalone anymore.
639+
640+ .. currentmodule:: django.contrib.auth.decorators
641+
642+ The ``permission_required`` decorator
643+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
565644
566645.. function:: permission_required(perm, [login_url=None, raise_exception=False])
567646
@@ -583,7 +662,7 @@ The permission_required decorator
583662 The decorator may also take an iterable of permissions.
584663
585664 Note that :func:`~django.contrib.auth.decorators.permission_required()`
586- also takes an optional ``login_url`` parameter. Example ::
665+ also takes an optional ``login_url`` parameter::
587666
588667 from django.contrib.auth.decorators import permission_required
589668
@@ -604,16 +683,74 @@ The permission_required decorator
604683 In older versions, the ``permission`` parameter only worked with
605684 strings, lists, and tuples instead of strings and any iterable.
606685
607- .. _applying-permissions-to-generic-views:
686+ .. currentmodule:: django.contrib.auth.mixins
608687
609- Applying permissions to generic views
688+ The ``PermissionRequiredMixin`` mixin
610689~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
611690
612- To apply a permission to a :doc:`class-based generic view
613- </ref/class-based-views/index>`, decorate the :meth:`View.dispatch
614- <django.views.generic.base.View.dispatch>` method on the class. See
615- :ref:`decorating-class-based-views` for details. Another approach is to
616- :ref:`write a mixin that wraps as_view() <mixins_that_wrap_as_view>`.
691+ To apply permission checks to :doc:`class-based views
692+ </ref/class-based-views/index>`, you can use the ``PermissionRequiredMixin``:
693+
694+ .. class:: PermissionRequiredMixin
695+
696+ .. versionadded:: 1.9
697+
698+ This mixin, just like the ``permisison_required``
699+ decorator, checks whether the user accessing a view has all given
700+ permissions. You should specify the permission (or an iterable of
701+ permissions) using the ``permission_required`` parameter::
702+
703+ from django.contrib.auth.mixins import PermissionRequiredMixin
704+
705+ class MyView(PermissionRequiredMixin, View):
706+ permission_required = 'polls.can_vote'
707+ # Or multiple of permissions:
708+ permission_required = ('polls.can_open', 'polls.can_edit')
709+
710+ You can set any of the parameters of
711+ :class:`~django.contrib.auth.mixins.AccessMixin` to customize the handling
712+ of unauthorized users.
713+
714+ Redirecting unauthorized requests in class-based views
715+ ------------------------------------------------------
716+
717+ To ease the handling of access restrictions in :doc:`class-based views
718+ </ref/class-based-views/index>`, the ``AccessMixin`` can be used to redirect a
719+ user to the login page or issue an HTTP 403 Forbidden response.
720+
721+ .. class:: AccessMixin
722+
723+ .. versionadded:: 1.9
724+
725+ .. attribute:: login_url
726+
727+ The URL that users who don't pass the test will be redirected to.
728+ Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
729+
730+ .. attribute:: permission_denied_message
731+
732+ When ``raise_exception`` is ``True``, this attribute can be used to
733+ control the error message passed to the error handler for display to
734+ the user. Defaults to an empty string.
735+
736+ .. attribute:: redirect_field_name
737+
738+ The name of the query parameter that will contain the URL the user
739+ should be redirected to after a successful login. If you set this to
740+ ``None``, a query parameter won't be added. Defaults to ``"next"``.
741+
742+ .. attribute:: raise_exception
743+
744+ If this attribute is set to ``True``, a
745+ :class:`~django.core.exceptions.PermissionDenied` exception will be
746+ raised instead of the redirect. Defaults to ``False``.
747+
748+ .. method:: handle_no_permission()
749+
750+ Depending on the value of ``raise_exception``, the method either raises
751+ a :exc:`~django.core.exceptions.PermissionDenied` exception or
752+ redirects the user to the ``login_url``, optionally including the
753+ ``redirect_field_name`` if it is set.
617754
618755.. _session-invalidation-on-password-change:
619756
0 commit comments