I have a basic Viewset:
class UsersViewSet(viewsets.ModelViewSet):
permission_classes = (OnlyStaff,)
queryset = User.objects.all()
serializer_class = UserSerializer
It is bind to the /api/users/
endpoint. I want to create a user profile page, so I need only a particular user, so I can retrieve it from /api/users/<id>/
, but the problem is that I want /api/users/<id>/
to be allowed to anyone, but /api/users/
to keep its permission OnlyStaff
, so no one can have access to the full list of users.
Note: Perhaps it's not such a good implementation, since anyone could brute force the data incremeting the id
, but I'm willing to change it from <id>
to <slug>
.
How can I delete the permission from detail route?
Thanks in advance.
Permissions in REST framework are always defined as a list of permission classes. Before running the main body of the view each permission in the list is checked. If any permission check fails, an exceptions.PermissionDenied or exceptions.NotAuthenticated exception will be raised, and the main body of the view will not run.
Tutorial 6: ViewSets & Routers REST framework includes an abstraction for dealing with ViewSets, that allows the developer to concentrate on modeling the state and interactions of the API, and leave the URL construction to be handled automatically, based on common conventions.
The following route would be generated: By default, the URL pattern is based on the method name, and the URL name is the combination of the ViewSet.basename and the hyphenated method name. If you don't want to use the defaults for either of these values, you can instead provide the url_path and url_name arguments to the @action decorator.
If you're writing your own views and want to enforce object level permissions, or if you override the get_object method on a generic view, then you'll need to explicitly call the .check_object_permissions (request, obj) method on the view at the point at which you've retrieved the object.
Override the get_permissions()
method as below
from rest_framework.permissions import AllowAny
class UsersViewSet(viewsets.ModelViewSet):
permission_classes = (OnlyStaff,)
queryset = User.objects.all()
serializer_class = UserSerializer
def get_permissions(self):
if self.action == 'retrieve':
return [AllowAny(), ]
return super(UsersViewSet, self).get_permissions()
It would help if you posted the permission class.
But going off what you posted, it appears that only staff users can have access to the endpoints bound to that viewset. Meaning no other user type/role can access those endpoints.
Going off your question, it seems like you want to setup a IsOwnerOrStaffOrReadOnly permission and over ride the list route function of the ModelViewSet and replace permission_classes and then call super
class UsersViewSet(viewsets.ModelViewSet):
permission_classes = (IsOwnerOrStaffOrReadOnly,)
queryset = User.objects.all()
serializer_class = UserSerializer
def list(self, request, *arg, **kwargs):
self.permission_classes = (OnlyStaffCanReadList,)
super(UsersViewSet, self).list(request, *args, **kwargs) // python3 super().list(request, *args, **kwargs)
is Owner object permission class
class IsOwnerOrStaffOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
if request.user.role == 'staff':
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user
only staff can read permission class
class OnlyStaffCanReadList(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.user.role == 'Staff':
return True
else:
return False
as provided in the comments, your user model must have the owner role. if you are using the django user model you can just do a obj.id == request.user.id
comparison
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