如何让 Django ViewSet 在匿名帖子上返回 403 错误

Mat*_*t D 3 django django-rest-framework

当匿名用户尝试 POST 时,我试图让我的应用程序返回 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)
Run Code Online (Sandbox Code Playgroud)

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

如何让它返回 403 代码?

xyr*_*res 5

您正尝试从 发送响应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)
Run Code Online (Sandbox Code Playgroud)