summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/releases/1.9.txt37
-rw-r--r--docs/topics/auth/default.txt161
-rw-r--r--docs/topics/class-based-views/intro.txt23
3 files changed, 186 insertions, 35 deletions
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index 63e1335333..2cd2ad018a 100644
--- a/docs/releases/1.9.txt
+++ b/docs/releases/1.9.txt
@@ -65,6 +65,43 @@ the included auth forms for your project, you could set, for example::
See :ref:`password-validation` for more details.
+Permission mixins for class-based views
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django now ships with the mixins
+:class:`~django.contrib.auth.mixins.AccessMixin`,
+:class:`~django.contrib.auth.mixins.LoginRequiredMixin`,
+:class:`~django.contrib.auth.mixins.PermissionRequiredMixin`, and
+:class:`~django.contrib.auth.mixins.UserPassesTestMixin` to provide the
+functionality of the ``django.contrib.auth.decorators`` for class-based views.
+These mixins have been taken from, or are at least inspired by, the
+`django-braces`_ project.
+
+There are a few differences between Django's and django-braces' implementation,
+though:
+
+* The :attr:`~django.contrib.auth.mixins.AccessMixin.raise_exception` attribute
+ can only be ``True`` or ``False``. Custom exceptions or callables are not
+ supported.
+
+* The :meth:`~django.contrib.auth.mixins.AccessMixin.handle_no_permission`
+ method does not take a ``request`` argument. The current request is available
+ in ``self.request``.
+
+* The custom ``test_func()`` of :class:`~django.contrib.auth.mixins.UserPassesTestMixin`
+ does not take a ``user`` argument. The current user is available in
+ ``self.request.user``.
+
+* The :attr:`permission_required <django.contrib.auth.mixins.PermissionRequiredMixin>`
+ attribute supports a string (defining one permission) or a list/tuple of
+ strings (defining multiple permissions) that need to be fulfilled to grant
+ access.
+
+* The new :attr:`~django.contrib.auth.mixins.AccessMixin.permission_denied_message`
+ attribute allows passing a message to the ``PermissionDenied`` exception.
+
+.. _django-braces: http://django-braces.readthedocs.org/en/latest/index.html
+
Minor features
~~~~~~~~~~~~~~
diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt
index f04a266cd8..cc8d0abc97 100644
--- a/docs/topics/auth/default.txt
+++ b/docs/topics/auth/default.txt
@@ -425,8 +425,8 @@ login page::
.. currentmodule:: django.contrib.auth.decorators
-The login_required decorator
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The ``login_required`` decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. function:: login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None])
@@ -500,6 +500,43 @@ The login_required decorator
:func:`django.contrib.admin.views.decorators.staff_member_required`
decorator a useful alternative to ``login_required()``.
+.. currentmodule:: django.contrib.auth.mixins
+
+The ``LoginRequired`` mixin
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using :doc:`class-based views </topics/class-based-views/index>`, you can
+achieve the same behavior as with ``login_required`` by using the
+``LoginRequiredMixin``. This mixin should be at the leftmost position in the
+inheritance list.
+
+.. class:: LoginRequiredMixin
+
+ .. versionadded:: 1.9
+
+ If a view is using this mixin, all requests by non-authenticated users will
+ be redirected to the login page or shown an HTTP 403 Forbidden error,
+ depending on the
+ :attr:`~django.contrib.auth.mixins.AccessMixin.raise_exception` parameter.
+
+ You can set any of the parameters of
+ :class:`~django.contrib.auth.mixins.AccessMixin` to customize the handling
+ of unauthorized users::
+
+
+ from django.contrib.auth.mixins import LoginRequiredMixin
+
+ class MyView(LoginRequiredMixin, View):
+ login_url = '/login/'
+ redirect_field_name = 'redirect_to'
+
+.. note::
+
+ Just as the ``login_required`` decorator, this mixin does NOT check the
+ ``is_active`` flag on a user.
+
+.. currentmodule:: django.contrib.auth.decorators
+
Limiting access to logged-in users that pass a test
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -560,8 +597,50 @@ redirects to the login page::
def my_view(request):
...
-The permission_required decorator
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. currentmodule:: django.contrib.auth.mixins
+
+.. class:: UserPassesTestMixin
+
+ .. versionadded:: 1.9
+
+ When using :doc:`class-based views </topics/class-based-views/index>`, you
+ can use the ``UserPassesTestMixin`` to do this.
+
+ You have to override the ``test_func()`` method of the class to provide
+ the test that is performed. Furthermore, you can set any of the parameters
+ of :class:`~django.contrib.auth.mixins.AccessMixin` to customize the
+ handling of unauthorized users::
+
+ from django.contrib.auth.mixins import UserPassesTestMixin
+
+ class MyView(UserPassesTestMixin, View):
+
+ def test_func(self):
+ return self.request.user.email.endswith('@example.com')
+
+ .. admonition: Stacking UserPassesTestMixin
+
+ Due to the way ``UserPassesTestMixin`` is implemented, you cannot stack
+ them in your inheritance list. The following does NOT work::
+
+ class TestMixin1(UserPassesTestMixin):
+ def test_func(self):
+ return self.request.user.email.endswith('@example.com')
+
+ class TestMixin2(UserPassesTestMixin):
+ def test_func(self):
+ return self.request.user.username.startswith('django')
+
+ class MyView(TestMixin1, TestMixin2, View):
+ ...
+
+ If ``TestMixin1`` would call ``super()`` and take that result into
+ account, ``TestMixin1`` wouldn't work standalone anymore.
+
+.. currentmodule:: django.contrib.auth.decorators
+
+The ``permission_required`` decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. function:: permission_required(perm, [login_url=None, raise_exception=False])
@@ -583,7 +662,7 @@ The permission_required decorator
The decorator may also take an iterable of permissions.
Note that :func:`~django.contrib.auth.decorators.permission_required()`
- also takes an optional ``login_url`` parameter. Example::
+ also takes an optional ``login_url`` parameter::
from django.contrib.auth.decorators import permission_required
@@ -604,16 +683,74 @@ The permission_required decorator
In older versions, the ``permission`` parameter only worked with
strings, lists, and tuples instead of strings and any iterable.
-.. _applying-permissions-to-generic-views:
+.. currentmodule:: django.contrib.auth.mixins
-Applying permissions to generic views
+The ``PermissionRequiredMixin`` mixin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-To apply a permission to a :doc:`class-based generic view
-</ref/class-based-views/index>`, decorate the :meth:`View.dispatch
-<django.views.generic.base.View.dispatch>` method on the class. See
-:ref:`decorating-class-based-views` for details. Another approach is to
-:ref:`write a mixin that wraps as_view() <mixins_that_wrap_as_view>`.
+To apply permission checks to :doc:`class-based views
+</ref/class-based-views/index>`, you can use the ``PermissionRequiredMixin``:
+
+.. class:: PermissionRequiredMixin
+
+ .. versionadded:: 1.9
+
+ This mixin, just like the ``permisison_required``
+ decorator, checks whether the user accessing a view has all given
+ permissions. You should specify the permission (or an iterable of
+ permissions) using the ``permission_required`` parameter::
+
+ from django.contrib.auth.mixins import PermissionRequiredMixin
+
+ class MyView(PermissionRequiredMixin, View):
+ permission_required = 'polls.can_vote'
+ # Or multiple of permissions:
+ permission_required = ('polls.can_open', 'polls.can_edit')
+
+ You can set any of the parameters of
+ :class:`~django.contrib.auth.mixins.AccessMixin` to customize the handling
+ of unauthorized users.
+
+Redirecting unauthorized requests in class-based views
+------------------------------------------------------
+
+To ease the handling of access restrictions in :doc:`class-based views
+</ref/class-based-views/index>`, the ``AccessMixin`` can be used to redirect a
+user to the login page or issue an HTTP 403 Forbidden response.
+
+.. class:: AccessMixin
+
+ .. versionadded:: 1.9
+
+ .. attribute:: login_url
+
+ The URL that users who don't pass the test will be redirected to.
+ Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
+
+ .. attribute:: permission_denied_message
+
+ When ``raise_exception`` is ``True``, this attribute can be used to
+ control the error message passed to the error handler for display to
+ the user. Defaults to an empty string.
+
+ .. attribute:: redirect_field_name
+
+ The name of the query parameter that will contain the URL the user
+ should be redirected to after a successful login. If you set this to
+ ``None``, a query parameter won't be added. Defaults to ``"next"``.
+
+ .. attribute:: raise_exception
+
+ If this attribute is set to ``True``, a
+ :class:`~django.core.exceptions.PermissionDenied` exception will be
+ raised instead of the redirect. Defaults to ``False``.
+
+ .. method:: handle_no_permission()
+
+ Depending on the value of ``raise_exception``, the method either raises
+ a :exc:`~django.core.exceptions.PermissionDenied` exception or
+ redirects the user to the ``login_url``, optionally including the
+ ``redirect_field_name`` if it is set.
.. _session-invalidation-on-password-change:
diff --git a/docs/topics/class-based-views/intro.txt b/docs/topics/class-based-views/intro.txt
index 6c1ec9233e..6724bec0da 100644
--- a/docs/topics/class-based-views/intro.txt
+++ b/docs/topics/class-based-views/intro.txt
@@ -173,29 +173,6 @@ that inherits from ``View`` - for example, trying to use a form at the top of a
list and combining :class:`~django.views.generic.edit.ProcessFormView` and
:class:`~django.views.generic.list.ListView` - won't work as expected.
-.. _mixins_that_wrap_as_view:
-
-Mixins that wrap ``as_view()``
-------------------------------
-
-One way to apply common behavior to many classes is to write a mixin that wraps
-the :meth:`~django.views.generic.base.View.as_view()` method.
-
-For example, if you have many generic views that should be decorated with
-:func:`~django.contrib.auth.decorators.login_required` you could implement a
-mixin like this::
-
- from django.contrib.auth.decorators import login_required
-
- class LoginRequiredMixin(object):
- @classmethod
- def as_view(cls, **initkwargs):
- view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
- return login_required(view)
-
- class MyView(LoginRequiredMixin, ...):
- # this is a generic view
- ...
Handling forms with class-based views
=====================================