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

Django中Ajax提交评论返回{"response":"forbidden"}错误求助

Django评论提交返回{"response":"forbidden"}问题排查

问题描述

在Django 4.2.6 + Python 3.11环境下实现文章评论功能,已有可用的评论表单,但提交时返回错误信息{"response":"forbidden"}。已确认表单有效、请求URL正确,提交评论的用户已登录并拥有相应权限,仍无法定位问题原因。

相关代码

Django表单代码

class CommentForm(forms.ModelForm):
    author = forms.CharField(required=True, error_messages={'required': 'لطفاً نام خود را وارد کنید.'})
    body = forms.CharField(required=True, error_messages={'required': 'لطفاً نظر خود را وارد کنید.'})

    class Meta:
        model = Comment
        fields = ('author', 'body', 'post')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.cleaned_data = {}

    def clean_author(self):
        author = self.cleaned_data.get('author', 'نام کاربری ناشناس')
        return author

    def clean_body(self):
        body = self.cleaned_data.get('body')
        return body

前端提交JS代码

function comment(slug, id) {
    var comment = document.getElementById("comment").value;

    $.post(`/posts/post/${slug}/comment/create/${id}`, {
    comment: comment
    }).then(response => {
        if (response['response'] === 'created') {
            var count = document.getElementById("count");
            count.innerText = Number(count.innerText) + 1;

            document.getElementById("comment").value = "";
        } else {
            var errors = response['errors'];
            for (var key in errors) {
                var error = errors[key];
                document.getElementById("comment").classList.add("is-invalid");
                document.getElementById("comment").setAttribute("aria-invalid", "true");
                document.getElementById("comment").setCustomValidity(error);
            }
        }
    });
}

环境

  • Django 4.2.6
  • Python 3.11

复现步骤

  • 进入文章页面
  • 点击“Leave a comment”按钮
  • 在评论框输入内容
  • 点击“Submit”按钮

预期与实际行为

  • 预期行为:评论创建成功并显示在文章页面
  • 实际行为:返回错误信息{"response":"forbidden"}

排查方向与解决办法

  1. CSRF令牌缺失
    Django默认启用CSRF保护,AJAX请求必须携带CSRF令牌,否则会返回403禁止访问。当前JS的$.post请求未包含CSRF令牌,这是最常见的原因。

    • 解决:
      1. 在页面模板中添加CSRF元标签:
        <meta name="csrf-token" content="{{ csrf_token }}">
        
      2. 在JS代码中全局设置AJAX请求头,或者在post请求中携带令牌:
        // 全局设置
        $.ajaxSetup({
            headers: { "X-CSRFToken": $('meta[name="csrf-token"]').attr('content') }
        });
        // 或者在post请求中添加参数
        $.post(`/posts/post/${slug}/comment/create/${id}`, {
            comment: comment,
            csrfmiddlewaretoken: $('meta[name="csrf-token"]').attr('content')
        })
        
  2. 表单初始化错误
    CommentForm的__init__方法中直接重置了self.cleaned_data = {},这会导致表单验证时无法获取用户提交的数据,进而触发后端异常或权限判断错误。

    • 解决:删除self.cleaned_data = {}这行代码,Django会自动处理cleaned_data的初始化与填充。
  3. 请求参数不匹配
    JS仅传递了comment参数,但表单需要author、body、post三个字段。若后端视图未正确处理参数映射,可能将验证失败错误误判为权限问题返回forbidden。

    • 解决:
      • 若author应为当前登录用户,后端视图中直接设置form.instance.author = request.user,无需前端传递;
      • post字段可通过URL中的id参数获取,后端自动关联到表单,无需前端传递;
      • JS中应将参数名改为body: comment,与表单字段对应。
  4. 视图权限逻辑问题
    即使用户已登录,视图可能存在额外的权限检查(如文章是否允许评论、用户是否被限制评论等),或未正确处理POST请求的权限验证。

    • 解决:检查视图代码:
      • 确认使用了@login_required装饰器(若评论需要登录);
      • 验证当前用户是否有权限评论目标文章;
      • 确保视图中表单验证失败时返回错误信息,而非错误地返回forbidden响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:43:22