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"}
排查方向与解决办法
CSRF令牌缺失
Django默认启用CSRF保护,AJAX请求必须携带CSRF令牌,否则会返回403禁止访问。当前JS的$.post请求未包含CSRF令牌,这是最常见的原因。- 解决:
- 在页面模板中添加CSRF元标签:
<meta name="csrf-token" content="{{ csrf_token }}"> - 在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') })
- 在页面模板中添加CSRF元标签:
- 解决:
表单初始化错误
CommentForm的__init__方法中直接重置了self.cleaned_data = {},这会导致表单验证时无法获取用户提交的数据,进而触发后端异常或权限判断错误。- 解决:删除
self.cleaned_data = {}这行代码,Django会自动处理cleaned_data的初始化与填充。
- 解决:删除
请求参数不匹配
JS仅传递了comment参数,但表单需要author、body、post三个字段。若后端视图未正确处理参数映射,可能将验证失败错误误判为权限问题返回forbidden。- 解决:
- 若
author应为当前登录用户,后端视图中直接设置form.instance.author = request.user,无需前端传递; post字段可通过URL中的id参数获取,后端自动关联到表单,无需前端传递;- JS中应将参数名改为
body: comment,与表单字段对应。
- 若
- 解决:
视图权限逻辑问题
即使用户已登录,视图可能存在额外的权限检查(如文章是否允许评论、用户是否被限制评论等),或未正确处理POST请求的权限验证。- 解决:检查视图代码:
- 确认使用了
@login_required装饰器(若评论需要登录); - 验证当前用户是否有权限评论目标文章;
- 确保视图中表单验证失败时返回错误信息,而非错误地返回forbidden响应。
- 确认使用了
- 解决:检查视图代码:
内容的提问来源于stack exchange,提问作者Elyas Shavikloo
相关产品推荐
相关产品推荐

