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

Django点赞按钮点击返回JsonResponse,需留在原页面不跳转

Django点赞按钮实现(无页面跳转/刷新)

问题核心

点击点赞按钮后跳转到JSON数据页,本质是未阻止浏览器默认页面跳转行为,同时视图存在请求方法未限制、用户操作逻辑不统一的小问题。


第一步:修正Django视图函数

  1. 限制请求仅接受POST(GET请求不应修改数据)
  2. 统一用户添加/移除的调用方式(避免对象与ID混用)
  3. 保留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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:46:08