You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中Post模型likes字段无法递增问题求助

Django博客点赞功能:Post.likes字段无法递增的解决方案

核心问题:自定义的like方法未被触发

你写的like方法根本没被调用,因为CreateAPIView默认处理POST请求的是create方法,不是你自定义的like方法,所以更新post.likes的代码完全没执行。

修复步骤

1. 覆盖CreateAPIView的post方法

把点赞逻辑放到post方法里,替换默认的create逻辑:

# views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework import generics, permissions
from django.db.models import F
from .models import Like, Post
from .serializers import LikeSerializer

class LikeView(generics.CreateAPIView):
    permission_classes = [permissions.IsAuthenticated]
    queryset = Like.objects.all()
    serializer_class = LikeSerializer
    
    def post(self, request, format=None):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            # 从验证后的安全数据中取值,比直接取serializer.data更可靠
            user = serializer.validated_data['user']
            post = serializer.validated_data['post']
            
            # 先检查是否已点赞,避免重复操作
            if Like.objects.filter(user=user, post=post).exists():
                return Response({"error": "你已经给这篇帖子点过赞了"}, status=status.HTTP_400_BAD_REQUEST)
            
            # 创建点赞记录
            like = Like.objects.create(user=user, post=post)
            
            # 数据库层面直接递增likes,避免并发计数错误
            Post.objects.filter(id=post.id).update(likes=F('likes') + 1)
            
            return Response(LikeSerializer(like).data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

2. 修正Like模型的字段与约束

你的Like模型外键命名不合理,还缺少重复点赞的约束:

# models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models import UniqueConstraint

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(auto_now_add=True)

    def __str__(self):
        return self.title

class Like(models.Model):
    # 字段名改为user和post,ForeignKey会自动生成_id后缀,避免混淆
    user = models.ForeignKey(User, related_name='user_likes', on_delete=models.CASCADE)
    post = models.ForeignKey(Post, related_name='post_likes', on_delete=models.CASCADE)
    
    class Meta:
        # 强制一个用户只能给同一篇帖子点一次赞
        constraints = [
            UniqueConstraint(fields=['user', 'post'], name='unique_user_post_like')
        ]
    
    def __str__(self):
        return f"{self.user.username} 点赞了 {self.post.title}"

3. 同步修改序列化器字段

因为Like模型字段名改了,序列化器也要对应调整:

# serializers.py
from rest_framework import serializers
from .models import Like

class LikeSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('user', 'post')
        model = Like

关键优化点

  • 用serializer.validated_data:这是经过序列化器验证后的干净数据,比直接取serializer.data更安全,避免脏数据。
  • 数据库层面更新:Post.objects.filter(id=post.id).update(likes=F('likes') + 1)直接在数据库执行递增,不需要先拉取对象到内存,效率更高,还能避免多个请求同时点赞时的计数错误。
  • 重复点赞检查:提前在代码层面判断,避免触发数据库的唯一约束异常,给用户更友好的提示。

内容的提问来源于stack exchange,提问作者user14611431

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:25:13