diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index 5cb3ec3c0..4845ac88e 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -150,7 +150,7 @@ As well as global permissions, that are run against all incoming requests, you c # Instance must have an attribute named `owner`. return obj.owner == request.user -Note that the generic views will check the appropriate object level permissions, but if you're writing your own custom views, you'll need to make sure you check the object level permission checks yourself, by calling `self.has_object_permission(request, obj)` from the view. +Note that the generic views will check the appropriate object level permissions, but if you're writing your own custom views, you'll need to make sure you check the object level permission checks yourself. You can do so by calling `self.check_object_permissions(request, obj)` from the view once you have the object instance. This call will raise an appropriate `APIException` if any object-level permission checks fail, and will otherwise simply return. [cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html [authentication]: authentication.md diff --git a/docs/api-guide/views.md b/docs/api-guide/views.md index 574020f9b..8b26b3e35 100644 --- a/docs/api-guide/views.md +++ b/docs/api-guide/views.md @@ -76,11 +76,11 @@ The following methods are used by REST framework to instantiate the various plug The following methods are called before dispatching to the handler method. -### .check_permissions(...) +### .check_permissions(self, request) -### .check_throttles(...) +### .check_throttles(self, request) -### .perform_content_negotiation(...) +### .perform_content_negotiation(self, request, force=False) ## Dispatch methods diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 19dca7e6c..9ae8cf0aa 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -131,8 +131,7 @@ class SingleObjectAPIView(SingleObjectMixin, GenericAPIView): Override default to add support for object-level permissions. """ obj = super(SingleObjectAPIView, self).get_object(queryset) - if not self.has_object_permission(self.request, obj): - self.permission_denied(self.request) + self.check_object_permissions(self.request, obj) return obj diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py index ce6331127..d898ca128 100644 --- a/rest_framework/mixins.py +++ b/rest_framework/mixins.py @@ -93,8 +93,7 @@ class UpdateModelMixin(object): except Http404: # If this is a PUT-as-create operation, we need to ensure that # we have relevant permissions, as if this was a POST request. - if not self.has_permission(clone_request(request, 'POST')): - self.permission_denied(self.request) + self.check_permissions(clone_request(request, 'POST')) created = True success_status_code = status.HTTP_201_CREATED else: diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index e7df87583..a65254042 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -21,8 +21,7 @@ from rest_framework.request import clone_request from rest_framework.utils import dict2xml from rest_framework.utils import encoders from rest_framework.utils.breadcrumbs import get_breadcrumbs -from rest_framework import VERSION, status -from rest_framework import parsers +from rest_framework import exceptions, parsers, status, VERSION class BaseRenderer(object): @@ -299,12 +298,10 @@ class BrowsableAPIRenderer(BaseRenderer): if not api_settings.FORM_METHOD_OVERRIDE: return # Cannot use form overloading - request = clone_request(request, method) try: - if not view.has_permission(request): - return # Don't have permission - except Exception: - return # Don't have permission and exception explicitly raise + view.check_permissions(clone_request(request, method)) + except exceptions.APIException: + return False # Doesn't have permissions return True def serializer_to_form_fields(self, serializer): diff --git a/rest_framework/views.py b/rest_framework/views.py index dd8889aeb..55ad8cf35 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -258,33 +258,28 @@ class APIView(View): return (renderers[0], renderers[0].media_type) raise - def has_permission(self, request, obj=None): + def check_permissions(self, request): """ - Return `True` if the request should be permitted. + Check if the request should be permitted. + Raises an appropriate exception if the request is not permitted. """ - if obj is not None: - warnings.warn('The `obj` argument in `has_permission` is due to be deprecated. ' - 'Use `has_object_permission()` instead for object permissions.', - PendingDeprecationWarning, stacklevel=2) - return self.has_object_permission(request, obj) - for permission in self.get_permissions(): if not permission.has_permission(request, self): - return False - return True + self.permission_denied(request) - def has_object_permission(self, request, obj): + def check_object_permissions(self, request, obj): """ - Return `True` if the request should be permitted for a given object. + Check if the request should be permitted for a given object. + Raises an appropriate exception if the request is not permitted. """ for permission in self.get_permissions(): if not permission.has_object_permission(request, self, obj): - return False - return True + self.permission_denied(request) def check_throttles(self, request): """ Check if request should be throttled. + Raises an appropriate exception if the request is throttled. """ for throttle in self.get_throttles(): if not throttle.allow_request(request, self): @@ -311,8 +306,7 @@ class APIView(View): self.format_kwarg = self.get_format_suffix(**kwargs) # Ensure that the incoming request is permitted - if not self.has_permission(request): - self.permission_denied(request) + self.check_permissions(request) self.check_throttles(request) # Perform content negotiation and store the accepted info on the request