aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbwreilly2013-09-07 23:48:03 -0500
committerbwreilly2013-09-07 23:48:03 -0500
commit9ff0f6d3bff3c1d02d2ccaf4f1500e25cb97620d (patch)
tree2b93a40da0a680290c15d3115ecae683016feb6a
parent118645e4806effaa35726012a983676b2c55b6dd (diff)
downloaddjango-rest-framework-9ff0f6d3bff3c1d02d2ccaf4f1500e25cb97620d.tar.bz2
switch to a dedicated filter for read list object permissions
-rw-r--r--rest_framework/filters.py18
-rw-r--r--rest_framework/permissions.py13
2 files changed, 23 insertions, 8 deletions
diff --git a/rest_framework/filters.py b/rest_framework/filters.py
index 4079e1bd..6d46ad23 100644
--- a/rest_framework/filters.py
+++ b/rest_framework/filters.py
@@ -4,7 +4,7 @@ returned by list views.
"""
from __future__ import unicode_literals
from django.db import models
-from rest_framework.compat import django_filters, six
+from rest_framework.compat import django_filters, six, guardian
from functools import reduce
import operator
@@ -23,6 +23,22 @@ class BaseFilterBackend(object):
raise NotImplementedError(".filter_queryset() must be overridden.")
+class ObjectPermissionReaderFilter(BaseFilterBackend):
+ """
+ A filter backend that limits results to those where the requesting user
+ has read object level permissions.
+ """
+ def __init__(self):
+ assert guardian, 'Using ObjectPermissionReaderFilter, but django-guardian is not installed'
+
+ def filter_queryset(self, request, queryset, view):
+ user = request.user
+ model_cls = queryset.model
+ model_name = model_cls._meta.module_name
+ permission = 'read_' + model_name
+ return guardian.shortcuts.get_objects_for_user(user, permission, queryset)
+
+
class DjangoFilterBackend(BaseFilterBackend):
"""
A filter backend that uses django-filter.
diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py
index 2d8a30e9..0d5e0e78 100644
--- a/rest_framework/permissions.py
+++ b/rest_framework/permissions.py
@@ -9,6 +9,7 @@ SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
from django.http import Http404
from rest_framework.compat import oauth2_provider_scope, oauth2_constants, guardian
+from rest_framework.filters import ObjectPermissionReaderFilter
class BasePermission(object):
@@ -169,7 +170,7 @@ class DjangoObjectLevelModelPermissions(DjangoModelPermissions):
'destroy': 'delete',
}
- def _get_names(self, view):
+ def _get_model_name(self, view):
model_cls = getattr(view, 'model', None)
queryset = getattr(view, 'queryset', None)
@@ -182,19 +183,17 @@ class DjangoObjectLevelModelPermissions(DjangoModelPermissions):
def has_permission(self, request, view):
if view.action == 'list':
- user = request.user
queryset = view.get_queryset()
- model_name = self._get_names(view)
- view.queryset = guardian.shortcuts.get_objects_for_user(user, 'read_' + model_name, queryset) #TODO: move to filter
+ view.queryset = ObjectPermissionReaderFilter().filter_queryset(request, queryset, view)
return super(DjangoObjectLevelModelPermissions, self).has_permission(request, view)
def has_object_permission(self, request, view, obj):
- user = request.user
- model_name = self._get_names(view)
action = self.action_perm_map.get(view.action)
-
assert action, "Tried to determine object permissions but no action specified in view"
+ user = request.user
+ model_name = self._get_model_name(view)
+
perm = "{action}_{model_name}".format(action=action, model_name=model_name)
check = user.has_perm(perm, obj)
if not check: