mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-27 08:50:40 +03:00
Unify QS handling for model/object permissions
This commit is contained in:
parent
af460d2b69
commit
23b2d8099b
|
@ -114,6 +114,21 @@ class DjangoModelPermissions(BasePermission):
|
||||||
|
|
||||||
return [perm % kwargs for perm in self.perms_map[method]]
|
return [perm % kwargs for perm in self.perms_map[method]]
|
||||||
|
|
||||||
|
def _queryset(self, view):
|
||||||
|
assert hasattr(view, 'get_queryset') \
|
||||||
|
or getattr(view, 'queryset', None) is not None, (
|
||||||
|
'Cannot apply {} on a view that does not set '
|
||||||
|
'`.queryset` or have a `.get_queryset()` method.'
|
||||||
|
).format(self.__class__.__name__)
|
||||||
|
|
||||||
|
if hasattr(view, 'get_queryset'):
|
||||||
|
queryset = view.get_queryset()
|
||||||
|
assert queryset is not None, (
|
||||||
|
'{}.get_queryset() returned None'.format(view.__class__.__name__)
|
||||||
|
)
|
||||||
|
return queryset
|
||||||
|
return view.queryset
|
||||||
|
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
# Workaround to ensure DjangoModelPermissions are not applied
|
# Workaround to ensure DjangoModelPermissions are not applied
|
||||||
# to the root view when using DefaultRouter.
|
# to the root view when using DefaultRouter.
|
||||||
|
@ -124,19 +139,7 @@ class DjangoModelPermissions(BasePermission):
|
||||||
not is_authenticated(request.user) and self.authenticated_users_only):
|
not is_authenticated(request.user) and self.authenticated_users_only):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if hasattr(view, 'get_queryset'):
|
queryset = self._queryset(view)
|
||||||
queryset = view.get_queryset()
|
|
||||||
assert queryset is not None, (
|
|
||||||
'{}.get_queryset() returned None'.format(view.__class__.__name__)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
queryset = getattr(view, 'queryset', None)
|
|
||||||
|
|
||||||
assert queryset is not None, (
|
|
||||||
'Cannot apply DjangoModelPermissions on a view that '
|
|
||||||
'does not set `.queryset` or have a `.get_queryset()` method.'
|
|
||||||
)
|
|
||||||
|
|
||||||
perms = self.get_required_permissions(request.method, queryset.model)
|
perms = self.get_required_permissions(request.method, queryset.model)
|
||||||
|
|
||||||
return request.user.has_perms(perms)
|
return request.user.has_perms(perms)
|
||||||
|
@ -183,16 +186,8 @@ class DjangoObjectPermissions(DjangoModelPermissions):
|
||||||
return [perm % kwargs for perm in self.perms_map[method]]
|
return [perm % kwargs for perm in self.perms_map[method]]
|
||||||
|
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
if hasattr(view, 'get_queryset'):
|
# authentication checks have already executed via has_permission
|
||||||
queryset = view.get_queryset()
|
queryset = self._queryset(view)
|
||||||
else:
|
|
||||||
queryset = getattr(view, 'queryset', None)
|
|
||||||
|
|
||||||
assert queryset is not None, (
|
|
||||||
'Cannot apply DjangoObjectPermissions on a view that '
|
|
||||||
'does not set `.queryset` or have a `.get_queryset()` method.'
|
|
||||||
)
|
|
||||||
|
|
||||||
model_cls = queryset.model
|
model_cls = queryset.model
|
||||||
user = request.user
|
user = request.user
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.test import TestCase
|
||||||
|
|
||||||
from rest_framework import (
|
from rest_framework import (
|
||||||
HTTP_HEADER_ENCODING, authentication, generics, permissions, serializers,
|
HTTP_HEADER_ENCODING, authentication, generics, permissions, serializers,
|
||||||
status
|
status, views
|
||||||
)
|
)
|
||||||
from rest_framework.compat import ResolverMatch, guardian, set_many
|
from rest_framework.compat import ResolverMatch, guardian, set_many
|
||||||
from rest_framework.filters import DjangoObjectPermissionsFilter
|
from rest_framework.filters import DjangoObjectPermissionsFilter
|
||||||
|
@ -219,6 +219,27 @@ class ModelPermissionsIntegrationTests(TestCase):
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
|
def test_queryset_assertions(self):
|
||||||
|
class View(views.APIView):
|
||||||
|
authentication_classes = [authentication.BasicAuthentication]
|
||||||
|
permission_classes = [permissions.DjangoModelPermissions]
|
||||||
|
view = View.as_view()
|
||||||
|
|
||||||
|
request = factory.get('/', HTTP_AUTHORIZATION=self.permitted_credentials)
|
||||||
|
msg = 'Cannot apply DjangoModelPermissions on a view that does not set `.queryset` or have a `.get_queryset()` method.'
|
||||||
|
with self.assertRaisesMessage(AssertionError, msg):
|
||||||
|
view(request)
|
||||||
|
|
||||||
|
# Faulty `get_queryset()` methods should trigger the above "view does not have a queryset" assertion.
|
||||||
|
class View(RootView):
|
||||||
|
def get_queryset(self):
|
||||||
|
return None
|
||||||
|
view = View.as_view()
|
||||||
|
|
||||||
|
request = factory.get('/', HTTP_AUTHORIZATION=self.permitted_credentials)
|
||||||
|
with self.assertRaisesMessage(AssertionError, 'View.get_queryset() returned None'):
|
||||||
|
view(request)
|
||||||
|
|
||||||
|
|
||||||
class BasicPermModel(models.Model):
|
class BasicPermModel(models.Model):
|
||||||
text = models.CharField(max_length=100)
|
text = models.CharField(max_length=100)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user