Fixed #24929 -- Allowed permission_required decorator to take any iterable

This commit is contained in:
Raphael Michel 2015-06-05 10:08:19 +02:00 committed by Tim Graham
parent 8b1f39a727
commit 39937de7e6
4 changed files with 22 additions and 2 deletions

View File

@ -4,6 +4,7 @@ from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.shortcuts import resolve_url from django.shortcuts import resolve_url
from django.utils import six
from django.utils.decorators import available_attrs from django.utils.decorators import available_attrs
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
@ -59,7 +60,7 @@ def permission_required(perm, login_url=None, raise_exception=False):
is raised. is raised.
""" """
def check_perms(user): def check_perms(user):
if not isinstance(perm, (list, tuple)): if isinstance(perm, six.string_types):
perms = (perm, ) perms = (perm, )
else: else:
perms = perm perms = perm

View File

@ -114,6 +114,10 @@ Minor features
a deprecation warning in older versions and is no longer supported in a deprecation warning in older versions and is no longer supported in
Django 1.9). Django 1.9).
* The permission argument of
:func:`~django.contrib.auth.decorators.permission_required()` accepts all
kinds of iterables, not only list and tuples.
:mod:`django.contrib.gis` :mod:`django.contrib.gis`
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -580,7 +580,7 @@ The permission_required decorator
(i.e. ``polls.can_vote`` for a permission on a model in the ``polls`` (i.e. ``polls.can_vote`` for a permission on a model in the ``polls``
application). application).
The decorator may also take a list of permissions. The decorator may also take an iterable of permissions.
Note that :func:`~django.contrib.auth.decorators.permission_required()` Note that :func:`~django.contrib.auth.decorators.permission_required()`
also takes an optional ``login_url`` parameter. Example:: also takes an optional ``login_url`` parameter. Example::
@ -599,6 +599,11 @@ The permission_required decorator
(HTTP Forbidden) view<http_forbidden_view>` instead of redirecting to the (HTTP Forbidden) view<http_forbidden_view>` instead of redirecting to the
login page. login page.
.. versionchanged:: 1.9
In older versions, the ``permission`` parameter only worked with
strings, lists, and tuples instead of strings and any iterable.
.. _applying-permissions-to-generic-views: .. _applying-permissions-to-generic-views:
Applying permissions to generic views Applying permissions to generic views

View File

@ -76,6 +76,16 @@ class PermissionsRequiredDecoratorTest(TestCase):
resp = a_view(request) resp = a_view(request)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
def test_many_permissions_in_set_pass(self):
@permission_required({'auth.add_customuser', 'auth.change_customuser'})
def a_view(request):
return HttpResponse()
request = self.factory.get('/rand')
request.user = self.user
resp = a_view(request)
self.assertEqual(resp.status_code, 200)
def test_single_permission_pass(self): def test_single_permission_pass(self):
@permission_required('auth.add_customuser') @permission_required('auth.add_customuser')