Generic views with row-level permission handling

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
from django.views.generic.detail import DetailView
from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.views.generic.list import ListView
from django.core import exceptions
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404, HttpResponseRedirect


class GuardedDetailView(DetailView):
    def get(self, request, **kwargs):
        self.object = self.get_object()
        self.check_permission(request.user, self.object)
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)


class GuardedUpdateView(UpdateView):
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.check_permission(request.user, self.object)
        return super(GuardedUpdateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.check_permission(request.user, self.object)
        return super(GuardedUpdateView, self).post(request, *args, **kwargs)


class GuardedCreateView(CreateView):
    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        if form.is_valid():
            self.ensure_permissions(request.user, form.instance)
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

class GuardedDeleteView(DeleteView):
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.check_permission(request.user, self.object)
        return super(DeleteView, self).get(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.check_permission(request.user, self.object)
        self.object.delete()
        return HttpResponseRedirect(self.get_success_url())


class OwnedCreateView(GuardedCreateView):
    
    owner = None
    
    def ensure_permissions(self, user, object):
        setattr(object, self.owner, user)

    
class OwnedDetailView(GuardedDetailView):
    
    owner = None
    
    def check_permission(self, user, object):
        if getattr(object, self.owner) != user:
            raise exceptions.PermissionDenied()


class OwnedUpdateView(GuardedUpdateView):
    
    owner = None
    
    def check_permission(self, user, object):
        if getattr(object, self.owner) != user:
            raise exceptions.PermissionDenied()

class OwnedDeleteView(GuardedDeleteView):
    
    owner = None
    
    def check_permission(self, user, object):
        if getattr(object, self.owner) != user:
            raise exceptions.PermissionDenied()


class OwnedListView(ListView):
    
    owner = None
    
    def get_queryset_perm(self, user):
        """
        Get the list of items for this view. This must be an interable, and may
        be a queryset (in which qs-specific behavior will be enabled).
        """
        if self.queryset is not None:
            queryset = self.queryset
            if hasattr(queryset, '_clone'):
                queryset = queryset._clone()
        elif self.model is not None:
            lookup_args = { self.owner: user }
            queryset = self.model._default_manager.filter(**lookup_args)
        else:
            raise ImproperlyConfigured(u"'%s' must define 'queryset' or 'model'"
                                       % self.__class__.__name__)
        return queryset

    def get(self, request, *args, **kwargs):
        self.object_list = self.get_queryset_perm(request.user)
        allow_empty = self.get_allow_empty()
        if not allow_empty and len(self.object_list) == 0:
            raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")
                          % {'class_name': self.__class__.__name__})
        context = self.get_context_data(object_list=self.object_list)
        return self.render_to_response(context)

More like this

  1. Class based generic views that automatically check permissions by humphreymurray 2 years, 5 months ago
  2. create_update for newforms (ModelForm) by Rozza 5 years, 3 months ago
  3. View Permission Decorator Helper by jgeewax 4 years, 11 months ago
  4. Owner required decorator by polarbear 4 years, 11 months ago
  5. create_object and update_object for newforms by danjak 6 years, 3 months ago

Comments

bradbeattie (on June 15, 2012):

To get this working, I had to modify getattr(object, "owner") and lookup_args = { "owner": user }.

#

(Forgotten your password?)