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
What are Object Level Permissions in DRF? In DRF, object level permissions are used to decide if a user should be allowed to interact with a particular object. The object is usually simply a model instance.
Django admin allows access to users marked as is_staff=True . To disable a user from being able to access the admin, you should set is_staff=False . This holds true even if the user is a superuser. is_superuser=True .
By default, Django automatically gives add, change, and delete permissions to all models, which allow users with the permissions to perform the associated actions via the admin site. You can define your own permissions to models and grant them to specific users.
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
The plumbing is there (this is from the bottom of the same page you linked):
Handling object permissions
Django's permission framework has a foundation for object permissions, though there is no implementation for it in the core. That means that checking for object permissions will always return False or an empty list (depending on the check performed). An authentication backend will receive the keyword parameters obj and user_obj for each object related authorization method and can return the object level permission as appropriate.
But no default implementation is provided. Since this is a common topic; there are lots of answers on SO. Check to the right and you'll see some listed.
The basis idea is to browse the django packages' perm grid and pick an implementation of object level permissions. I personally like django-guardian.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With