These generic views extend default views so that they also do permission checking on per-object basis.
- detail, update and delete - check access for user
- create - create permissions for user on object
- list - narrow object list with permissions
Classes prefixed with Owned are example implementation where user has access to object if designed object attribute references him.
Example:
create_article = OwnedCreateView.as_view(owner='creator', model=Article, form_class=ArticleForm, success_url='/articles/article/%(id)d')
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
- Template tag - list punctuation for a list of items by shapiromatron 9 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 9 months, 1 week ago
- Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 4 months ago
- Help text hyperlinks by sa2812 1 year, 5 months ago
Comments
To get this working, I had to modify getattr(object, "owner") and lookup_args = { "owner": user }.
#
Please login first before commenting.