Django点赞按钮点击返回JsonResponse,需留在原页面不跳转
Django点赞按钮实现(无页面跳转/刷新)
问题核心
点击点赞按钮后跳转到JSON数据页,本质是未阻止浏览器默认页面跳转行为,同时视图存在请求方法未限制、用户操作逻辑不统一的小问题。
第一步:修正Django视图函数
- 限制请求仅接受POST(GET请求不应修改数据)
- 统一用户添加/移除的调用方式(避免对象与ID混用)
- 保留JsonResponse返回点赞数数据
from django.http import JsonResponse from django.shortcuts import get_object_or_404 from django.views.decorators.http import require_POST from .models import Post @require_POST # 仅允许POST请求,防止GET误操作 def liking(request, pk): posts = get_object_or_404(Post, id=pk) if request.user.is_authenticated: # 先校验用户登录状态 if request.user in posts.likes.all(): posts.likes.remove(request.user) else: posts.likes.add(request.user) # 直接传入用户对象,而非ID likes_count = posts.likes.count() # 简化计数逻辑 data = {'likes_count': likes_count} return JsonResponse(data, status=200) # 未登录用户返回错误提示 return JsonResponse({'error': '请先登录'}, status=401)
第二步:前端JavaScript实现(阻止跳转+异步请求)
通过JS绑定点击事件,阻止浏览器默认跳转行为,用异步请求提交点赞操作,最后更新页面点赞数。
示例HTML按钮结构
<!-- 每个帖子的点赞按钮,通过data-post-id存储帖子ID --> <button class="like-btn" data-post-id="{{ post.id }}"> 点赞 <span class="like-count">{{ post.likes.count }}</span> </button>
示例JavaScript代码
// 批量绑定所有点赞按钮的点击事件 document.querySelectorAll('.like-btn').forEach(btn => { btn.addEventListener('click', async (e) => { e.preventDefault(); // 关键:阻止浏览器默认跳转/刷新行为 const postId = btn.dataset.postId; const likeCountEl = btn.querySelector('.like-count'); try { // 发送POST请求,带上Django要求的CSRF令牌 const response = await fetch(`/your-url-path/liking/${postId}/`, { method: 'POST', headers: { 'X-CSRFToken': getCookie('csrftoken'), 'Content-Type': 'application/json' } }); const data = await response.json(); if (response.ok) { // 实时更新页面上的点赞数 likeCountEl.textContent = data.likes_count; // 可选:切换按钮样式(比如点赞后高亮) btn.classList.toggle('liked'); } else { alert(data.error || '点赞操作失败'); } } catch (error) { console.error('请求异常:', error); alert('网络错误,请稍后重试'); } }); }); // 辅助函数:从Cookie中获取CSRF令牌(Django默认存储逻辑) function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }
关键注意事项
- 必须用
@require_POST装饰器限制请求方法,避免GET请求修改数据库 - 前端必须调用
e.preventDefault(),这是解决空白页跳转问题的核心 - 发送POST请求时必须携带CSRF令牌,否则Django会拒绝请求
- 视图中需校验用户登录状态,防止未登录用户操作点赞
内容的提问来源于stack exchange,提问作者Rodolfo Schiavi
相关产品推荐
相关产品推荐

