Home > Back-end >  Increment Integer Field in Django
Increment Integer Field in Django

Time:11-20

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',)
    
  • Related