diff options
| -rw-r--r-- | rest_framework/filters.py | 18 | ||||
| -rw-r--r-- | rest_framework/permissions.py | 13 |
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: |
