Django中Ajax点赞按钮异常:循环内外均出问题求助
问题描述
原本实现了常规点赞按钮,运行正常但页面刷新体验不佳,引入Ajax优化后出现两个问题:
- 将Ajax脚本放在
{% for post in posts %}循环外时,必须手动刷新页面才能看到点赞状态变化 - 将脚本放在循环内时,点赞计数器出现混乱,页面所有帖子的点赞/取消状态都会被反转
相关代码
posts/urls.py
urlpatterns = [ path('create/', PostCreateView.as_view(), name='create_post'), path('like/', like_view, name='like_post'), path('<int:pk>/update/', PostUpdateView.as_view(), name='update_post'), path('<int:pk>/delete/', PostDeleteView.as_view(), name='delete_post'), path('<int:pk>/', PostDetailView.as_view(), name='detail_post'), ]
posts/views.py
def like_view(request, *args, **kwargs): post = get_object_or_404(Post, id=request.POST.get('post_id')) if post.likes.filter(id=request.user.id).exists(): post.likes.remove(request.user) else: post.likes.add(request.user) context = { 'post': post, } if is_ajax(request): html = render_to_string('like_template.html', context, request=request) return JsonResponse({'form': html})
post_inclde.html(被引入用户个人主页和信息流页面)
<script> $(document).ready(function(){ $(document).on('click', '#like', function(event){ event.preventDefault(); var pk = $(this).attr('value'); $.ajax({ type: 'POST', url: '{% url \"like_post\" request.user.slug %}', data: { 'post_id': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}' }, success: function(response){ $('#like_section_{{ post.id }}').html(response['form']) }, error: function(rs, e){ console.log(rs.responseText); }, }); crossDomain: false }); }) </script> {% if posts %} {% for post in posts %} <div class="card mb-3 border-0 shadow"> <h5 class="card-title">{{ post.title }}</h5> {{ post.body|safe }} </div> {% include 'like_template.html' %} {% endfor %} {% endif %}
like_template.html
<div id="like_section_{{ post.id }}"> <div class="row mb-3"> <div class="col-md-4 d-flex justify-content-start"> <form action="{% url 'like_post' post.author.slug %}" method="POST"> {% csrf_token %} {% if request.user in post.likes.all %} <button type="submit" id="like" name="post_id" value="{{ post.id }}" class="btn btn-primary btn-sm" style="border-radius: 60px;"> <img src="{% static 'icons/heartbreak-fill.svg' %}" alt="Unlike Icon" width="16" height="16"> {{ post.total_likes }} </button> {% else %} <button type="submit" id="like" name="post_id" value="{{ post.id }}" class="btn btn-primary btn-sm" style="border-radius: 60px;"> <img src="{% static 'icons/heart-fill.svg' %}" alt="Like Icon" width="16" height="16"> {{ post.total_likes }} </button> {% endif %} </form> <button type="submit" name="post_id" value="{{ post.id }}" class="btn btn-primary btn-sm ms-2" style="border-radius: 60px;" onclick="hide_comments('comment_section_{{ post.id }}')"> <img src="{% static 'icons/chat-fill.svg' %}" alt="Post Comments Icon" width="16" height="16"> {{ post.comments.count }} </button> </div> </div> </div>
问题分析与修复方案
核心问题1:重复ID引发的事件绑定混乱
HTML中ID必须唯一,但所有点赞按钮都用了id="like",循环内生成的多个重复ID会导致:
- 脚本放循环外时,事件委托能触发,但回调里的
{{ post.id }}不在循环上下文,无法渲染出具体帖子ID,找不到目标DOM更新状态 - 脚本放循环内时,会生成多份重复的事件绑定,点击任意按钮会触发所有绑定事件,导致所有帖子状态反转
核心问题2:URL匹配错误
urls.py中like_post的路径是path('like/', ...),不接收slug参数,但模板中{% url "like_post" request.user.slug %}和form的action="{% url 'like_post' post.author.slug %}"都错误传递了slug,会导致请求失败。
具体修复步骤
替换唯一ID为类名
修改like_template.html中的按钮ID为类,避免重复:<!-- 已点赞状态按钮 --> <button type="submit" class="like-btn" name="post_id" value="{{ post.id }}" class="btn btn-primary btn-sm" style="border-radius: 60px;"> <img src="{% static 'icons/heartbreak-fill.svg' %}" alt="Unlike Icon" width="16" height="16"> {{ post.total_likes }} </button> <!-- 未点赞状态按钮 --> <button type="submit" class="like-btn" name="post_id" value="{{ post.id }}" class="btn btn-primary btn-sm" style="border-radius: 60px;"> <img src="{% static 'icons/heart-fill.svg' %}" alt="Like Icon" width="16" height="16"> {{ post.total_likes }} </button>修正Ajax脚本,动态获取目标区域
将脚本放在循环外,修改事件绑定为类选择器,通过点击按钮动态定位对应点赞区域:<script> $(document).ready(function(){ $(document).on('click', '.like-btn', function(event){ event.preventDefault(); var $btn = $(this); var pk = $btn.attr('value'); // 找到当前按钮所属的点赞区域ID var sectionId = $btn.closest('[id^="like_section_"]').attr('id'); $.ajax({ type: 'POST', url: '{% url "like_post" %}', data: { 'post_id': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}' }, success: function(response){ $('#' + sectionId).html(response['form']) }, error: function(rs, e){ console.log(rs.responseText); }, crossDomain: false }); }); }) </script>修正form的action属性
修改like_template.html中的form路径,去掉多余的slug参数:<form action="{% url 'like_post' %}" method="POST">
内容的提问来源于stack exchange,提问作者jmur
相关产品推荐
相关产品推荐

