解决Django评论点赞按钮点击出现NoReverseMatch错误且Ajax无法自动更新的问题
解决Django评论点赞的NoReverseMatch错误及Ajax状态更新问题
看起来你遇到的核心问题是Ajax请求的URL路径不完整,导致Django找不到对应的路由,同时还有几个小细节(比如重复ID、CSRF传递方式)影响了功能正常工作。让我们一步步解决:
问题根源分析
- 路由路径不匹配:你的URL配置是
post/<int:pk>/like-comment,但Ajax请求里直接用了"like-comment",缺少了前面的post/<post_id>/部分,Django无法解析这个路由,所以抛出NoReverseMatch。 - 静态JS无法解析模板变量:你的
main.js是静态文件,里面的{{ csrf_token }}不会被Django模板引擎渲染,导致CSRF token传递错误(虽然你加了csrf_exempt,但这不是最佳实践)。 - 重复DOM ID:所有评论的点赞按钮都用了
id="like-comment",DOM中ID必须唯一,这会导致点击事件绑定混乱,只有第一个按钮能正常触发。
分步解决方案
1. 修正Ajax请求的URL和CSRF传递方式(main.js)
把选择器从ID改成class,构建完整的URL,并从页面元标签获取CSRF token:
$(document).ready(function(){ // 用class选择器绑定事件,避免重复ID问题 $(document).on('click', '.like-comment-btn', function(event){ event.preventDefault(); const commentId = $(this).val(); // 评论ID const postId = $(this).data('post-id'); // 帖子ID // 构建完整的请求URL const url = `/post/${postId}/like-comment`; // 从页面元标签获取CSRF token const csrfToken = $('meta[name="csrf-token"]').attr('content'); $.ajax({ type: 'POST', url: url, data: { 'id': commentId, 'csrfmiddlewaretoken': csrfToken }, dataType: 'json', success: function(response) { // 更新对应评论的点赞区域,用唯一ID定位 $(`#like-section-comment-${commentId}`).html(response.form); }, error: function(rs, e) { console.error('点赞请求失败:', rs.responseText); }, }); }); });
2. 修改评论模板,确保唯一标识(comment_section.html)
给每个评论的点赞区域添加唯一ID,同时把按钮的ID改成class:
<article class="media content-section"> {% if user.is_authenticated %} <!-- 给每个评论的点赞区域加唯一ID,方便Ajax更新 --> <div id="like-section-comment-{{ comment.id }}"> <form method="post"> {% csrf_token %} {% if request.user in comment.likes.all %} <button type="submit" class="like-comment-btn btn btn-danger btn-sm" name="comment_id" data-post-id="{{ comment.post.id }}" value="{{ comment.id }}"> Dislike </button> {% else %} <button type="submit" class="like-comment-btn btn btn-primary btn-sm" name="comment_id" data-post-id="{{ comment.post.id }}" value="{{ comment.id }}"> Like </button> {% endif %} <span class="ml-2">{{ comment.likes.count }} 赞</span> </form> </div> {% endif %} </article>
同时确保你的base.html里有CSRF元标签(如果没有的话加上):
<meta name="csrf-token" content="{{ csrf_token }}">
3. 优化视图函数(可选,移除csrf_exempt)
既然我们已经正确传递了CSRF token,就可以去掉@csrf_exempt装饰器,恢复CSRF保护:
# 移除@csrf_exempt def like_comment(request, pk): comment = get_object_or_404(Comment, id=request.POST.get('id')) liked = False if comment.likes.filter(id=request.user.id).exists(): comment.likes.remove(request.user) liked = False else: comment.likes.add(request.user) liked = True context = { 'comment': comment, 'is_liked': liked, 'total_likes': comment.likes.count() } if request.headers.get('x-requested-with') == 'XMLHttpRequest': # 更准确的Ajax判断 html = render_to_string('blog/like_section_comment.html', context, request=request) return JsonResponse({'form': html}) return redirect('post-detail', pk=pk) # 非Ajax请求的 fallback
4. 确保like_section_comment.html模板正确
你的like_section_comment.html应该是评论点赞区域的片段,和上面模板里的内容一致,比如:
<form method="post"> {% csrf_token %} {% if is_liked %} <button type="submit" class="like-comment-btn btn btn-danger btn-sm" name="comment_id" data-post-id="{{ comment.post.id }}" value="{{ comment.id }}"> Dislike </button> {% else %} <button type="submit" class="like-comment-btn btn btn-primary btn-sm" name="comment_id" data-post-id="{{ comment.post.id }}" value="{{ comment.id }}"> Like </button> {% endif %} <span class="ml-2">{{ total_likes }} 赞</span> </form>
测试验证
- 重启Django服务器
- 打开帖子页面,点击任意评论的点赞按钮,应该能看到按钮立即切换成Dislike/Like,点赞数同步更新,页面无需刷新
- 检查浏览器控制台,如果还有错误,查看Network面板里的请求URL是否正确(应该是
/post/[post_id]/like-comment)
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

