【问题标题】:How to use has_object_permission with APIView in Django Rest Framework?如何在 Django Rest Framework 中使用 has_object_permission 和 APIView?
【发布时间】:2020-10-07 17:30:28
【问题描述】:

大家好,我想在我的类 UserDetail 中使用 APIView 的自定义权限,但我注意到此权限没有执行,我的权限称为“IsOwner”,因为我想允许用户根据用户身份。每次我提出请求时都会出错:

{
    "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) 这行不行)

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)

【问题讨论】:

  • 如果你删除 IsOwner,它可以工作吗?
  • 你确定存在User 这样的pk 吗?响应 {"detail": "Not found."} 表示在 UserDetail.get_object() 中引发了 404。
  • @Vincent 如果我删除 self.check_object_permissions(self.request, user) 正在工作
  • @wiaterb pk 是正确的,因为如果我评论此行现在正在工作 self.check_object_permissions(self.request, user)
  • permission_classes 应该是元组,例如:permission_classes = (CustomObjectPermissions, isOwner)

标签: python python-3.x django api django-rest-framework


【解决方案1】:

如果需要运算符或者,可以导入rest_condition:

pip install rest_condition

在你看来 import Or from rest_condition 并在 permission_classes 上执行以下操作:

permission_classes = [Or(CustomObjectPermissions,IsOwner)]

但我不认为错误是因为 Or 丢失引起的,您可以从另一个角度解决此问题,您可以让 get 请求仅返回该用户的信息,以便他可以修改:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-22
    • 2013-05-06
    • 1970-01-01
    • 2020-09-30
    • 1970-01-01
    相关资源
    最近更新 更多