Is there a way to do row level permissions in django? I thought there wasn't but just noticed this in the docs:
Permissions can be set not only per type of object, but also per specific object instance. By using the has_add_permission(), has_change_permission() and has_delete_permission() methods provided by the ModelAdmin class, it is possible to customize permissions for different object instances of the same type.
https://docs.djangoproject.com/en/dev/topics/auth/
But i don't see any documentation on how to actually implement per instance permissions
For an application i'm building i want to provide row level permission through a simple decorator. I can do this because the condition is just whether the request.user is the owner of the model object.
Following seems to work:
from functools import wraps
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
def is_owner_permission_required(model, pk_name='pk'):
def decorator(view_func):
def wrap(request, *args, **kwargs):
pk = kwargs.get(pk_name, None)
if pk is None:
raise RuntimeError('decorator requires pk argument to be set (got {} instead)'.format(kwargs))
is_owner_func = getattr(model, 'is_owner', None)
if is_owner_func is None:
raise RuntimeError('decorator requires model {} to provide is_owner function)'.format(model))
o=model.objects.get(pk=pk) #raises ObjectDoesNotExist
if o.is_owner(request.user):
return view_func(request, *args, **kwargs)
else:
raise PermissionDenied
return wraps(view_func)(wrap)
return decorator
The view:
@login_required
@is_owner_permission_required(Comment)
def edit_comment(request, pk):
...
Urls:
url(r'^comment/(?P<pk>\d+)/edit/$', 'edit_comment'),
The model:
class Comment(models.Model):
user = models.ForeignKey(User, ...
<...>
def is_owner(self, user):
return self.user == user
Any feedback or remarks are appreciated.
Paul Bormans