I am creating a simple blogging application and would like users to be able to like a post.
In terms of scalability I've decided it would be best to have likes as a separate table made up of pointers to both the user and post.
I have managed to enable the post request adding a like to the model however the likes
field in the post model is not incrementing.
I've tried using a simple likes = 1
technique in the serializer but that made no changes and have now used an F
string but still no changes are being made. I am still fairly new to Django and suspect it may be because I'm trying to update a field on a different model within a CreateAPIView
serializer but I'm not sure.
This is what I have so far
# views.py
class LikeView(generics.CreateAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
queryset = Like.objects.all()
serializer_class = LikeSerializer
def like(self, request, format=None):
serializer = self.serializer_class(data=request.data)
if(serializer.is_valid()):
user_id = serializer.data.get('user_id')
post_id = serializer.data.get('post_id')
l = Like(user_id=user_id, post_id=post_id)
l.save()
# likes field not updating with this
post = Post.objects.get(id=post_id)
post.likes = F('likes') 1
post.save()
return Response(LikeSerializer(l).data, status=status.HTTP_200_OK)
return Response(serializer.errors(), status=status.HTTP_400_BAD_REQUEST)
#models.py
class Post(models.Model):
id = models.CharField(max_length=36, default=generate_unique_id, primary_key=True)
title = models.CharField(max_length=50)
content = models.TextField()
likes = models.IntegerField(default=0, blank=True)
pub_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
class Like(models.Model):
user_id = models.ForeignKey(User, related_name='user_id', on_delete=models.CASCADE)
post_id = models.ForeignKey(Post, related_name='post_id', on_delete=models.CASCADE)
def __str__(self):
return "%s %s" % (self.user_id, self.post_id)
#serializers.py
class LikeSerializer(serializers.ModelSerializer):
class Meta:
fields= (
'user_id',
'post_id'
)
model = Like
Thank you
CodePudding user response:
You can use F()
only when doing queries.
post = Post.objects.get(id=post_id)
post.likes = post.likes 1
post.save()
or if you don't mind doing one more query, but also make sure that the post has always the correct number of likes:
post = Post.objects.get(id=post_id)
post.likes = Like.objects.filter(post=post).count()
post.save()
CodePudding user response:
The main reason for the likes were not getting updated was because, in the LikeView, you wrote
def like(self, request, format=None):
instead of
def post(self, request, *args, **kwargs):
Update the view as follows:
class LikeView(generics.CreateAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
queryset = Like.objects.all()
serializer_class = LikeSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
if (serializer.is_valid()):
like = serializer.save()
post = like.post_id
post.likes = post.post_id.count()
post.save()
return Response(LikeSerializer(like).data,
status=status.HTTP_200_OK)
return Response(serializer.errors(),
status=status.HTTP_400_BAD_REQUEST)
In the above code, you saved the Like object to a variable like
Then got the post object, and found the count using related name
of post foreign key.
Additionally, your model structure enables one user to like a post multiple times. To prevent that you can add the unique together to the Likes model.
class Like(models.Model):
user_id = models.ForeignKey(User, related_name='user_id', on_delete=models.CASCADE)
post_id = models.ForeignKey(Post, related_name='post_id', on_delete=models.CASCADE)
def __str__(self):
return "%s %s" % (self.user_id, self.post_id)
class Meta:
unique_together = ('user_id', 'post_id',)