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

Django上下投票系统故障:点踩按钮触发点赞功能

问题根源与解决方案

核心问题

你的点踩按钮触发点赞逻辑,本质是视图未区分按钮提交的操作类型,且当前PostVote视图会同时执行点赞和点踩的切换逻辑,导致点踩操作被覆盖;另外模板中按钮ID重复、业务逻辑未处理点赞点踩互斥,也加剧了问题。


步骤1:修正模板代码(区分操作类型+修复重复ID)

将两个按钮的name统一为vote_type,分别传递up和down作为操作标识,同时修复重复的id:

<div class="row">
    <div class="col-1">
        <strong>
            {% if user.is_authenticated %}
            <form action="{% url 'post_vote' post.slug %}" class="d-inline" method="POST">
                {% csrf_token %}
                {% if liked %}
                <button type="submit" name="vote_type" value="up" id="btn-upvote" class="btn-like"><i 
                    class="fa-solid fa-circle-up" style="color: #1ea427;"></i></button>
                {% else %}
                <button type="submit" name="vote_type" value="up" id="btn-upvote" class="btn-like"><i 
                    class="fa-regular fa-circle-up"></i></button>
                {% endif %}
            </form>
            {% else%}
            <span class="text-scondary"><i class="fa-regular fa-circle-up"></i></span>
            {% endif %}
            <span class="text-secondary">{{ post.number_of_up_votes}}</span>
        </strong>
    </div>
    <div class="col-1">
        <strong>
            {% if user.is_authenticated %}
            <form action="{% url 'post_vote' post.slug %}" class="d-inline" method="POST">
                {% csrf_token %}
                {% if disliked %}
                <button type="submit" name="vote_type" value="down" id="btn-downvote" class="btn-like"><i 
                    class="fa-solid fa-circle-down" style="color: #ff0000;"></i></button>
                {% else %}
                <button type="submit" name="vote_type" value="down" id="btn-downvote" class="btn-like"><i 
                    class="fa-regular fa-circle-down"></i></button>
                {% endif %}
            </form>
            {% else%}
            <span class="text-scondary"><i class="fa-regular fa-circle-down"></i></span>
            {% endif %}
            <span class="text-secondary">{{ post.number_of_down_votes}}</span>
        </strong>
    </div>
    <div class="col-1">
        {% with comments.count as total_comments %}
        <strong class="text-secondary"><i class="far fa-comments"></i>
            {{ total_comments }}</strong>
        {% endwith %}
    </div>
</div>

步骤2:重写PostVote视图(区分操作+处理互斥逻辑)

根据提交的vote_type执行对应操作,同时确保用户不能同时点赞和点踩:

class PostVote(View):

    def post(self, request, slug):
        post = get_object_or_404(Post, slug=slug)
        vote_type = request.POST.get('vote_type')

        if vote_type == 'up':
            # 处理点赞:如果已点赞则取消,否则先取消点踩再添加点赞
            if post.up_vote.filter(id=request.user.id).exists():
                post.up_vote.remove(request.user)
            else:
                post.down_vote.remove(request.user)
                post.up_vote.add(request.user)
        elif vote_type == 'down':
            # 处理点踩:如果已点踩则取消,否则先取消点赞再添加点踩
            if post.down_vote.filter(id=request.user.id).exists():
                post.down_vote.remove(request.user)
            else:
                post.up_vote.remove(request.user)
                post.down_vote.add(request.user)

        return HttpResponseRedirect(reverse('post_detail', args=[slug]))

步骤3:简化PostDetail中的状态判断

原代码用elif会导致逻辑不够直观,改为直接判断是否存在关联,更清晰:

class PostDetail(View):

    def get(self, request, slug, *args, **kwargs):
        queryset = Post.objects.filter(status=1)
        post = get_object_or_404(queryset, slug=slug)
        comments = post.comments.filter(approved=True).order_by('created_on')
        # 直接判断用户是否在点赞/点踩集合中
        liked = post.up_vote.filter(id=self.request.user.id).exists()
        disliked = post.down_vote.filter(id=self.request.user.id).exists()

        return render(
            request,
            "post_detail.html",
            {
                "post": post,
                "comments": comments,
                "commented": False,
                "liked": liked,
                "disliked": disliked,
                "comment_form": CommentForm(),
            },
        )
    
    # post方法中的liked/disliked判断也做同样修改
    def post(self, request, slug, *args, **kwargs):
        queryset = Post.objects.filter(status=1)
        post = get_object_or_404(queryset, slug=slug)
        comments = post.comments.filter(approved=True).order_by('-created_on')
        liked = post.up_vote.filter(id=self.request.user.id).exists()
        disliked = post.down_vote.filter(id=self.request.user.id).exists()

        # ... 其余代码保持不变

问题解释

  1. 原视图逻辑错误:之前的PostVote会同时执行点赞和点踩的切换,不管点哪个按钮,都会先修改点赞状态,再修改点踩状态,导致点踩操作的效果被覆盖。
  2. 模板未传递操作标识:原按钮的name分别为blogpost_id和blogdownpost_id,视图未判断这两个参数,无法区分操作类型。
  3. HTML ID重复:两个按钮使用相同的id="btn-like",违反HTML唯一性规则,可能导致前端交互异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:07:03