如何用Django结合Ajax实现类Instagram的主页直接点赞功能
解决Django主页批量帖子的Ajax点赞问题
问题根源
核心问题是DOM元素id重复:循环渲染帖子时,所有点赞按钮用了同一个id="btn_1",所有点赞数span用了同一个id="like_count",而DOM中id必须唯一,导致点击事件只会绑定到第一个按钮,成功回调也只会更新第一个点赞数。另外Ajax里获取帖子ID的写法错误,$('post_id').val()无法正确拿到目标帖子ID。
修复步骤
1. 修改主模板(解决id重复问题)
把固定id改成动态唯一标识,用帖子ID区分每个按钮和点赞数容器:
{% load static %} {% if user.is_authenticated %} {% if obj %} <h1 style="background:skyblue;text-align:center;">Posts</h1> {% for obj in obj %} <div style="background:lightgrey;border-radius:5px;margin-bottom:20px;padding:1rem;" data-post-id="{{ obj.id }}"> <p>{{obj.user}}</p> <p>{{obj.post_name}}</p> <!-- 修正原模板字段名错误:obj.name → obj.post_name --> <img height="250px" width="100%" src="{{ obj.image.url }}" alt="Image"> <p>{{obj.desription}}</p> <!-- 把固定id改为类,按钮value绑定帖子ID --> <button class="like-btn" type="button" value="{{ obj.id }}">Like</button> <!-- 给点赞数span设置唯一id --> <span id="like-count-{{ obj.id }}">{{obj.like_count}}</span> <h4>add a comment</h4> {% include "comments.html" %} </div> {% endfor %} {% else %} <h1 style="background:skyblue;text-align:center;">No Posts available</h1> {% endif %} {% endif %} {% csrf_token %} <!-- 统一放置csrf token,方便Ajax获取 -->
2. 修改Ajax代码(绑定正确事件,更新对应元素)
监听类选择器.like-btn的点击事件,从当前按钮获取帖子ID,成功后更新对应帖子的点赞数:
<script src="{% static 'jquery-3.6.0.js' %}" type="text/javascript"></script> <script> $(document).on('click', '.like-btn', function(e){ e.preventDefault(); const $btn = $(this); const postid = $btn.val(); // 从点击的按钮拿到当前帖子ID $.ajax({ type: 'POST', url: "{% url 'post_like' %}", data: { postid: postid, csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(), action: 'post' }, success: function(json){ // 更新当前帖子对应的点赞数span $("#like-count-" + postid).html(json['result']); console.log(json); }, error: function(xhr, errmsg, err){ console.error('点赞失败:', errmsg); } }); }); </script>
3. 视图与模型无需修改
你的LikeView视图逻辑、模型中的like_count属性计算逻辑都是正确的,URL配置也没问题,不需要改动。
验证效果
刷新主页后,点击任意帖子的点赞按钮,对应的点赞数会实时更新,不会再出现只有第一个按钮生效的问题。
内容的提问来源于stack exchange,提问作者sameerAhmedjan
相关产品推荐
相关产品推荐

