Reputation: 2350
I'm trying to get my app to return a 403 error when an anonymous user attempts to POST to it. Right now it returns a 201 code, but doesn't save the post to the database.
The problem is that my unit test fails because it's checking for a 403 code.
Here is my views
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)
You can see I'm checking if the user is authenticated and if not, return a Response with a 403 code, but for some reason a 201 code is being returned.
How do I get it to return a 403 code?
Upvotes: 3
Views: 2696
Reputation: 21779
You are trying to send a response from perform_create
, but this can't be done. You see, DRF (Django REST Framework) doesn't call the perform_create
method in a straight-forward manner. What happens is that DRF first calls CreateModelMixin
's create
method. Which then calls the perform_create
method and then returns the response.
In, short, the response is returned by the create
method, not perform_create
method. And the create
method, by default, returns the 201
status code (or sometimes 400
).
So, you will need to override the create
method instead. First, take a look at the source code for this method. Now, override:
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)
Upvotes: 5