如何让Django ViewSet在匿名发帖时返回403错误

ebdffaop  于 2023-01-06  发布在  Go
关注(0)|答案(2)|浏览(148)

我试图让我的应用程序返回一个403错误时,一个匿名用户试图向它发布。现在它返回一个201代码,但不保存帖子到数据库。
问题是我的单元测试失败了,因为它正在检查403代码。
以下是我的看法

from post.models import Post
from post.serializers import PostSerializer
from post.permissions import IsOwnerOrReadOnly, IsOwnerOrAdmin
from rest_framework import viewsets, status
from rest_framework.response import Response

class PostViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.
    """
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    # The default will be that anyone can read a post, but only owners can change it
    permission_classes = (IsOwnerOrReadOnly,)

    def get_permissions(self):
        # Both owners and admins can destroy a post, so if we're destroying we change permissions
        if self.action in ('destroy',):
            self.permission_classes = [IsOwnerOrAdmin, ]
        return super(self.__class__, self).get_permissions()

    def perform_create(self, serializer):
        if self.request.user.is_authenticated:
            serializer.save(author=self.request.user)
        else:
            return Response('Cannot post anonymously', status=status.HTTP_403_FORBIDDEN)

您可以看到,我正在检查用户是否经过身份验证,如果没有,则返回一个带有403代码的响应,但由于某种原因,返回了一个201代码。
我怎样才能让它返回一个403代码?

dgenwo3n

dgenwo3n1#

您尝试从perform_create发送响应,但无法实现。您可以看到,DRF(Django REST Framework)并没有以“直接”的方式调用perform_create方法。实际情况是DRF首先调用CreateModelMixincreate方法,然后调用perform_create方法,然后返回响应。
简而言之,响应是由create方法返回的,而不是perform_create方法,并且create方法在默认情况下返回201状态码(有时是400)。
所以,你需要重写create方法。首先,看看这个方法的源代码。现在,重写:

from rest_framework.exceptions import PermissionDenied

def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)

    if request.user.is_authenticated:
        self.perform_create(serializer)
    else:
        raise PermissionDenied('Cannot post anonymously')

    headers = self.get_success_headers(serializer.data)
    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
but5z9lq

but5z9lq2#

不要使用return,而是使用raise。
拒绝提升权限

相关问题