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

时间:2017-06-17 16:48:15

标签: 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)

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

如何让它返回403代码?

1 个答案:

答案 0 :(得分:2)

编辑:这个答案的旧版本是垃圾,并没有解决问题。所以不得不改变所有这一切。

您正尝试从perform_create发送回复,但无法完成此操作。您看,DRF(Django REST Framework)不以直接方式调用perform_create方法。会发生什么事情是DRF首先调用CreateModelMixincreate方法。然后调用perform_create方法,然后返回响应。

简而言之,响应是由create方法返回的,而不是perform_create方法。默认情况下,create方法会返回201状态代码(或有时400)。

因此,您需要覆盖create方法。首先,请查看此方法的source code。现在,覆盖:

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)