Reputation: 633
Using DRF to set up a plateform where users can share content, I'm having trouble checking if the author matches the logged user.
Example of a content model :
class Post(models.Model):
date = models.DateTimeField()
author = models.ForeignKey(User)
content = models.CharField(max_length=512)
Content serializer :
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
Content view :
@authentication_classes((SessionAuthentication, BasicAuthentication,))
@permission_classes((IsAuthenticated,))
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
http_method_names = ['get', 'post', 'head', 'options',]
I want post requests to perform a post.author == request.user test before saving the post.
On one hand my intuition tells me I should overwrite the create method of the view, with that kind of code (not tested, but here I just want to give an idea of what I want to do) :
class PostViewSet(viewsets.ModelViewSet):
[...]
def create(self, request):
post = self.get_object()
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
if serializer.validated_data.author == request.user:
serializer.save()
return Response({'message': 'Post saved !'})
else:
return Response({'message': 'You can't post for someone else'})
else:
return Response({'message': 'Not valid...'})
On the other hand, when I search for similar problems on my favorite search engine I can only find answers which involve overwriting the create/update methods in the serializer class.
I'm not very familiar with rest apis nor with DRF, but I'm confused, because what I'm talking about is kind of a custom permission (permissions are handled in views, right ?).
Looking for good practices tips :)
Upvotes: 2
Views: 1551
Reputation: 6013
It does not make much sense to leave the author
field editable to the user and then verify its value, you can just set it for the user in the create
. So in your serializer it would be:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
read_only_fields = ('author',)
Then in PostViewSet
, instead of your create
:
def perform_create(self, serializer):
serializer.save(author=self.request.user)
perform_create
is a hook which is called from create
after the data validation, so you don't have to bother doing it and creating the Response
yourself.
When you do updates or deletes though, you can add a custom permission class like IsAuthorOrReadOnly
which verifies that post.author == request.user
. You can inspire yourself from the second example here (IsOwnerOrReadOnly
class) which corresponds exactly to your needs.
You can then use it as any other permission class e.g.:
@permission_classes((IsAuthenticated, IsAuthorOrReadOnly, ))
class PostViewSet(viewsets.ModelViewSet):
# ...
Upvotes: 4