How to use has_object_permission with APIView in Django Rest Framework?

Viewed 1118

Hi everyone I want to use a custom permission with APIView in my class UserDetail but I noticed that this permission is not executing, my permission is called "IsOwner", because I want to allow users to modify his own information based on the user id. Every time that I make a request I got an error:

{
    "detail": "Not found."
}

views.py

from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework import status, permissions, generics, viewsets
from rest_framework.response import Response
from rest_framework.views import APIView

from .serializers import MyTokenObtainPairSerializer, UserSerializer, GroupSerializer
from .models import User
from authentication.permisssions import CustomObjectPermissions, IsOwner
from django.contrib.auth.models import Group
from django.http import Http404

class ObtainTokenPairView(TokenObtainPairView):
    permission_classes = [permissions.AllowAny,]
    serializer_class = MyTokenObtainPairSerializer

class UserList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    permission_classes = [CustomObjectPermissions]
    serializer_class = UserSerializer

    def get_queryset(self):
        users = User.objects.all().order_by('-date_joined')
        return users

    def get(self, request, format=None):

        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(self.get_queryset(), context=serializer_context, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(data=request.data, context=serializer_context)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class UserDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """

    permission_classes = [CustomObjectPermissions|IsOwner]

    serializer_class = UserSerializer

    def get_queryset(self):
        pk = self.kwargs["pk"]
        return User.objects.filter(id = pk)

    def get_object(self, pk):
        try:
            print(pk)
            user = User.objects.get(pk=pk)
            self.check_object_permissions(self.request, user)

            return user
        except User.DoesNotExist:

            raise Http404

    def get(self, request, pk, format=None):

        user = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(user, context=serializer_context)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        user = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(user,context=serializer_context, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        user = self.get_object(pk)
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class GroupList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    permission_classes = [CustomObjectPermissions]
    queryset = Group.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer

    def get(self, request, format=None):
        groups = Group.objects.all()
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(groups, context=serializer_context, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(data=request.data, context=serializer_context)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class GroupDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """

    permission_classes = [CustomObjectPermissions]
    queryset = Group.objects.all().order_by('-date_joined')
    serializer_class = GroupSerializer


    def get_object(self, pk):
        try:
            return Group.objects.get(pk=pk)
        except Group.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        group = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(group, context=serializer_context)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        group = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(group,context=serializer_context, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        group = self.get_object(pk)
        group.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

permissions.py

from rest_framework.permissions import DjangoObjectPermissions, BasePermission

class CustomObjectPermissions(DjangoObjectPermissions):
    """
    Similar to `DjangoObjectPermissions`, but adding 'view' permissions.
    """
    perms_map = {
        'GET': ['%(app_label)s.view_%(model_name)s'],
        'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
        'HEAD': ['%(app_label)s.view_%(model_name)s'],
        'POST': ['%(app_label)s.add_%(model_name)s'],
        'PUT': ['%(app_label)s.change_%(model_name)s'],
        'PATCH': ['%(app_label)s.change_%(model_name)s'],
        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
    }

class IsOwner(BasePermission):
    message = 'You must be the owner of this object'

    def has_object_permission(self, request, view, obj):
        return obj.id == request.user.id

views.py (self.check_object_permissions(self.request, user) this line is not working)

from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework import status, permissions, generics, viewsets
from rest_framework.response import Response
from rest_framework.views import APIView

from .serializers import MyTokenObtainPairSerializer, UserSerializer, GroupSerializer
from .models import User
from authentication.permisssions import CustomObjectPermissions, IsOwner
from django.contrib.auth.models import Group
from django.http import Http404

class ObtainTokenPairView(TokenObtainPairView):
    permission_classes = [permissions.AllowAny,]
    serializer_class = MyTokenObtainPairSerializer

class UserList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    permission_classes = [CustomObjectPermissions]
    serializer_class = UserSerializer

    def get_queryset(self):
        users = User.objects.all().order_by('-date_joined')
        return users

    def get(self, request, format=None):

        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(self.get_queryset(), context=serializer_context, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(data=request.data, context=serializer_context)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class UserDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """

    permission_classes = [CustomObjectPermissions|IsOwner]

    serializer_class = UserSerializer

    def get_queryset(self):
        pk = self.kwargs["pk"]
        return User.objects.filter(id = pk)

    def get_object(self, pk):
        try:
            print(pk)
            user = User.objects.get(pk=pk)
            self.check_object_permissions(self.request, user)

            return user
        except User.DoesNotExist:

            raise Http404

    def get(self, request, pk, format=None):

        user = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(user, context=serializer_context)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        user = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = UserSerializer(user,context=serializer_context, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        user = self.get_object(pk)
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class GroupList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    permission_classes = [CustomObjectPermissions]
    queryset = Group.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer

    def get(self, request, format=None):
        groups = Group.objects.all()
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(groups, context=serializer_context, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(data=request.data, context=serializer_context)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class GroupDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """

    permission_classes = [CustomObjectPermissions]
    queryset = Group.objects.all().order_by('-date_joined')
    serializer_class = GroupSerializer


    def get_object(self, pk):
        try:
            return Group.objects.get(pk=pk)
        except Group.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        group = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(group, context=serializer_context)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        group = self.get_object(pk)
        serializer_context = {
        'request': request,
        }
        serializer = GroupSerializer(group,context=serializer_context, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        group = self.get_object(pk)
        group.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
1 Answers

If you need the operator Or ,you can import rest_condition:

pip install rest_condition

And in your view import Or from rest_condition and do the following on the permission_classes:

permission_classes = [Or(CustomObjectPermissions,IsOwner)]

But I don't think the error is caused because Or is missing,you can tackle this problem from another prespective, you can have the get request returning only that user's information so he can modify:

def get_queryset(self):
   serializer = self.get_serializer()
   owner = serializer.context['request'].user
   return User.objects.filter(id=owner.id)
Related