How to add custom permission in viewset in django rest framework other than the default permission while creating a module?
I have a permission "fix_an_appointment". In the below viewset, how to include this permission? Those who have this permission has only able to create.
My views.py file:
class settingsViewSet(viewsets.ModelViewSet):
serializer_class = SettingsSerializer
queryset = Setting.objects.all()
Can anyone help?
I can't use a decorator like: #permission_classes(IsAuthenticated, ) in extra actions within ViewSet
To use different permissions in actions, instead, put it into the #action() as a parameter.
#action(detail=True, methods=['post'], permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
...
drf doc
simply create a custom permission class
class FixAnAppointmentPermssion(permissions.BasePermission):
def has_permission(self, request, view):
return True or False
then the in your view set class use your custom permission
class settingsViewSet(viewsets.ModelViewSet):
serializer_class = SettingsSerializer
queryset = Setting.objects.all()
permission_classes = (FixAnAppointmentPermssion,)
by docs custom-permissions, list of view actions actions
my_permissions.py
from rest_framework import permissions
class FixPermission(permissions.BasePermission):
"""
fix_an_appointment
"""
def has_permission(self, request, view):
if request.user.is_authenticated :
if view.action == 'retrieve':
return request.user.has_perms('fix_list_perm')
if view.action == 'retrieve':
return request.user.has_perms('fix_an_appointment')
return False
in views.py
from my_permissions import FixPermission
class settingsViewSet(viewsets.ModelViewSet):
serializer_class = SettingsSerializer
queryset = Setting.objects.all()
permission_classes = (FixPermission,)
We can set permission for each functions like create, retrive, update, delete(add,edit,delete and update)
from my_permissions import FixPermission
class FixAnAppointmentPermssion(permissions.BasePermission):
def has_permission(self, request, view):
return True or False
class YourViewSet(viewsets.ModelViewSet):
serializer_class = SettingsSerializer
queryset = Your.objects.all()
#permission_classes(FixAnAppointmentPermssion,)
def create(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
#permission_classes(FixAnAppointmentPermssion,)
def retrive(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Related
My problem is very simple : I'm trying to create some custom permissions for my django rest API. This is my code (permission.py) :
class UserPermissions(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj == request.user
I just want that the users can only get, delete and update their own account.
The problem is that I think my code is not read by Django. I have try to always return false (without any condition) and it does nothing. I have also try to print some debug message at the beginning of the file and it's does nothing.
(My file permissions.py is at the root of my application)$
This is my user view (UserView.py) :
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by("-date_joined")
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
swagger_tag = ["User"]
class LoginView(KnoxLoginView):
"""
API endpoint allowing the user to login and receive a token
"""
permission_classes = [
permissions.AllowAny,
]
#swagger_auto_schema(request_body=AuthTokenSerializer)
def post(self, request, format=None):
serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data["user"]
login(request, user)
return super(LoginView, self).post(request, format=None)
As #UtkucanBıyıklı says in their comment, you should specify the permission in the ViewSet:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.order_by('-date_joined')
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated, UserPermissions]
swagger_tag = ['User']
I'm trying to filter lists according to:
the user can work with all of their lists
the user can use safe methods on public lists
I have this code:
In views.py:
class LinkListViewSet(viewsets.ModelViewSet,
generics.ListAPIView,
generics.RetrieveAPIView):
queryset = LinkList.objects.all()
serializer_class = LinkListSerializer
permission_classes = [IsOwnerOrPublic]
In permissions.py:
class IsOwnerOrPublic(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticated
def has_object_permission(self, request, view, obj):
return obj.owner == request.user or (
obj.public and (request.method in SAFE_METHODS))
The problem is, I believe the view just skips checking the permission classes and returns all lists, and I am not sure why, or how to fix it.
It will only check the has_object_permission for requests that work with an object, so for example the RetrieveAPIView, not the ListAPIView.
You should filter for the latter, so we can make a custom IsOwnerOrPublicFilterBackend filter backend:
from django.db.models import Q
from rest_framework import filters
class IsOwnerOrPublicFilterBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
return queryset.filter(Q(owner=request.user) | Q(public=True))
and then use that filter as filter_backend in the ModelViewSet:
class LinkListViewSet(viewsets.ModelViewSet):
queryset = LinkList.objects.all()
serializer_class = LinkListSerializer
filter_backends = [IsOwnerOrPublicFilterBackend]
permission_classes = [IsOwnerOrPublic]
I need to check different types of permissions for different types of actions from request user. For example get permission only need [IsAuthenticated] but when user request perform_create method. I want to implement another permission that is CanCreateProject
permissions.py
class CanCreateProject(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.user.is_superuser:
return True
else:
return request.user.profile_limitation.can_create_project
views.py
class ProjectView(ModelViewSet):
serializer_class = ProjectSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
queryset = Project.objects.all()
organization = self.request.user.organization
query_set = queryset.filter(organization=organization)
return query_set
def perform_create(self, serializer):
self.permission_classes = [CanCreateProject] ## here
project = self.request.data["project_name"]
path = self.request.data["project_name"]
organization = self.request.data["organization"]
serializer.save(project_name=project, project_path=path, organization=organization)
How can I run the CanCreateProject method only for perform_create method is requested.
Override the get_permissions(...) method
class ProjectView(ModelViewSet):
serializer_class = ProjectSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
queryset = Project.objects.all()
organization = self.request.user.organization
query_set = queryset.filter(organization=organization)
return query_set
def get_permissions(self):
if self.action == 'create':
composed_perm = IsAuthenticated & CanCreateProject
return [composed_perm()]
return super().get_permissions()
# def perform_create(self, serializer):
# self.permission_classes = [CanCreateProject] ## here
#
# project = self.request.data["project_name"]
# path = self.request.data["project_name"]
# organization = self.request.data["organization"]
# serializer.save(project_name=project, project_path=path,
# organization=organization)
Notes:
You really don't need to use perform_create(...) method here
a possible dup: DRF Viewset remove permission for detail route
Update-1
You should implement the has_permission(..) method of the Permission class, not has_object_permission(...) method
from rest_framework import permissions
class CanCreateProject(permissions.BasePermission):
def has_permission(self, request, view):
if request.user.is_superuser:
return True
else:
return request.user.profile_limitation.can_create_project
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.
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
I have a django model and and i want that model to be accessed only by its owner(user who created the model). So i created a permission class as follows
class IsOwnerOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user
and applied this permission on modelviewset
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
permission_classes = (IsOwnerOnly,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
While accessing a single item it works, But even then every authenticated user can access the list of items. So how could i limit the item access to only its owner?
I have included Tokenauthentication in settings page as shown
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
}
and the item looks like
class Item(models.Model):
name=models.CharField(max_length=30)
address=models.TextField()
owner = models.ForeignKey('auth.User', related_name='items', on_delete=models.CASCADE)
def __str__(self):
return self.name
You can't control who can access item list by owner,if you what,you need to override has_permission to class IsOwnerOnly, like:
class IsAuthenticatedOwner(permissions.BasePermission):
def has_permission(self, request, view):
# work when your access /item/
if request.user and is_authenticated(request.user):
if request.user.id in [1, 2, 3]:
return True
else:
return False
else:
return False
def has_object_permission(self, request, view, obj):
# work when your access /item/item_id/
# Instance must have an attribute named `owner`.
return obj.owner == request.user
Notice:has_permission work when your access /item/(list),has_object_permission work when your access /item/item_id/(retrieve and update).
If you want to let user see the items only he created,simple as:
class ItemsViewSet(ModelViewSet):
queryset = Items.objects.all()
serializer_class = ItemsSerializer
permission_classes = (IsAuthenticated)
def get_queryset(self):
queryset = self.get_queryset().filter(owner=self.request.user)
return queryset
You can override the method get_queryset on your View
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
permission_classes = (IsOwnerOnly,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
This way the method list (from ModelViewSet) will call your "get_queryset" to build the pagination with the data.