There doesn't seem to be a way to have different permissions for list and detail views in a ViewSet. My use case is that I have a users api that exposes email addresses, I only want admins to be able to list all users, users should only be able to access their own user.
Perhaps there could be class variables such as permission_classes_list and permisssion_classes_detail or something like that.
Maybe this isn't such a good idea, I could just make 2 apis instead, one for admins and one for users.
I have the same use case and solved it by adding both a custom permission class and overriding the get_queryset method on the ModelViewSet.
This deals with the access to detail views:
class IsOwnerOrAdmin(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to see and edit it.
Admin users however have access to all.
"""
def has_object_permission(self, request, view, obj):
# Permissions are only allowed to the owner of the snippet
if request.user.is_staff:
return True
return obj.owner == request.user
And this deals with listing only the proper objects in the list view:
def get_queryset(self):
"""
Filter objects so a user only sees his own stuff.
If user is admin, let him see all.
"""
if self.request.user.is_staff:
return MyModel.objects.all()
else:
return MyModel.objects.filter(owner=self.request.user)
You already have the IsSelfOrAdmin permission class.
@j0hnsmith For your particular use case I'd recommend a filter class, that returns all users for admin access, and only returns the requestee's user for non-admin access.
Note that permission classes can check view.action for view sets - which would return either detail or list and allow you to implement different permissioning between each case.
Finally, if you really do need different behaviour in each case you can always drop down to using regular views, which will allow you to specify a different set of policy classes on each view.
thanks, I'll look into that.
@tomchristie Good to know there is a view.action.
Can I re-open this issue? Here's why:
1) I don't want to split my ViewSet into individual view functions because I want to leverage the Router to automatically generate consistent URLs.
2) I don't want to write some FrankenPermission with lots of conditionals because I have existing Permission classes that are small, elegant, and do exactly what I need, if only I could apply them on a per-method basis in my ViewSet.
3) The suggestions to use a Filter are good, but don't apply to my situation.
Thanks!
Nope 'friad not.
One option would be to build a permission class that allows you to delegate to two or more differing permission classes based on the request method. Take a look at eg the third party 'composed permissions' package here as an example of the kind of way you could deal with this without needing to make any changes to the core of REST framework... https://github.com/niwibe/djangorestframework-composed-permissions
@tomchristie
Hi Tom,
In your answer above on Jan 20, 2014, you said:
@j0hnsmith For your particular use case I'd recommend a filter class, that returns all users for admin access, and only returns the requestee's user for non-admin access.
By "filter class", do you mean filtering the get_queryset() as described below?
http://www.django-rest-framework.org/api-guide/filtering/
@jmtoung I assume he means a custom filter backend.
It should be expected behaviour when using permission class which restricts access to certain objects to also filter those objects out from the list.
If it cannot be implemented it should be mentioned in the docs.
If it cannot be implemented it should be mentioned in the docs.
http://www.django-rest-framework.org/api-guide/permissions/#djangoobjectpermissions
Note: If you need object level view permissions for GET, HEAD and OPTIONS requests, you'll want to consider also adding the DjangoObjectPermissionsFilter class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions.
I must be blind, thank you!
no, you are not. Would welcome some documentation improvements such as including links to that section from the others so it's more obvious.
Most helpful comment
http://www.django-rest-framework.org/api-guide/permissions/#djangoobjectpermissions