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

Django五星评分系统遇CSRF缺失403错误,寻求解决方法

Django五星评分系统403 CSRF缺失问题解决

问题根源

你遇到的403错误核心原因是:点击星星发起的AJAX POST请求没有携带CSRF令牌。虽然模板里加了{% csrf_token %},但这个标签只会生成一个表单隐藏字段,AJAX请求不会自动带上这个字段的值,所以Django的CSRF防护机制拦截了请求。

另外代码还有两个次要问题:

  • 模板里的表单字段重复使用form.first_name,last_name和comment字段都写错了
  • 视图没有区分AJAX请求和普通表单提交,AJAX只传rating的情况下,表单验证会失败

解决方案

1. 给AJAX请求添加CSRF令牌

有两种常用方式:

方式一:直接从页面获取csrf_token字段值

修改JS代码,把csrfmiddlewaretoken加入请求数据:

$(document).ready(function(){
    $('.rate .rate-item').on('click', function(){
        var value = $(this).data('value');
        // 获取页面上的csrf令牌值
        var csrfToken = $('input[name="csrfmiddlewaretoken"]').val();
        $.ajax({
            url: '{{ product.get_absolute_url }}',
            type: 'POST',
            data: {
                'rating': value,
                'csrfmiddlewaretoken': csrfToken
            },
            success: function(response){
                alert('Rating saved successfully!');
            }
        });
    });
});

方式二:通过请求头传递CSRF令牌

先添加一个获取Cookie的辅助函数,再设置请求头:

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;
}

$(document).ready(function(){
    $('.rate .rate-item').on('click', function(){
        var value = $(this).data('value');
        const csrftoken = getCookie('csrftoken');
        $.ajax({
            url: '{{ product.get_absolute_url }}',
            type: 'POST',
            headers: {
                'X-CSRFToken': csrftoken
            },
            data: {'rating': value},
            success: function(response){
                alert('Rating saved successfully!');
            }
        });
    });
});

2. 修正模板表单字段错误

模板里last_name和comment都错误使用了form.first_name,改成对应字段:

<form method="post">                                             
<div class="row">
<div class="col-md-6">
<div class="form-singel">
{{ form.first_name|attr:" placeholder:First name" }}
</div>
</div>
<div class="col-md-6">
<div class="form-singel">
{{ form.last_name|attr:" placeholder:Last Name"}}
</div>
</div>
<div class="col-lg-12">
<div class="form-singel">
<div class="rate-wrapper">
<div class="rate-label">Your Rating:</div>
<div class="rate">
<div data-value="1" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="2" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="3" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="4" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="5" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
</div>
</div>
</div>
</div>
<div class="col-lg-12">
<div class="form-singel">
{{ form.comment|attr:" placeholder:Comment" }}                                                                                               
</div>
</div>
{% csrf_token %} 
<div class="col-lg-12">
<div class="form-singel">
<button type="submit" class="main-btn">Post Comment</button>
</div>
</div>
</div> <!-- row -->                                 
</form>

3. 调整视图逻辑,区分AJAX和表单提交

当前视图里,AJAX只传rating的情况下,form.is_valid()会失败(因为first_name等必填字段为空),所以需要单独处理AJAX请求:

from django.http import JsonResponse

def productDetailView(request, id, slug):
    product = get_object_or_404(Product, id=id, slug=slug, available=True)
    new_comment = None
    
    if request.method == 'POST':
        # 判断是否是AJAX请求
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            # 处理AJAX评分提交
            rating = request.POST.get('rating')
            if rating and rating.isdigit() and 1 <= int(rating) <=5:
                # 示例:创建评分记录,实际场景需根据业务调整,比如关联用户
                review = Review(course=product, rating=int(rating))
                review.save()
                return JsonResponse({'status': 'success'})
            else:
                return JsonResponse({'status': 'error', 'message': 'Invalid rating'})
        else:
            # 处理普通表单提交
            form = ReviewForm(request.POST)
            if form.is_valid():
                new_comment = form.save(commit=False)
                new_comment.course = product
                new_comment.save()
    else:
        form = ReviewForm()
    
    return render(request, 'shop/product_detail.html', {'product': product, 'form': form})

额外说明

  • 确保你的ReviewForm里包含了rating字段,否则表单提交时rating不会被正确处理
  • 生产环境中,AJAX提交评分时要做用户身份验证,防止匿名用户重复提交

内容的提问来源于stack exchange,提问作者MMEEUR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 02:50:27