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

Django表单验证失效:form.errors未返回400请求,超长内容未被拦截

问题与解决方案

问题描述

提交表单时,内容超过设置的240字符限制,但表单未触发验证错误,后端也没有返回Bad Request响应,模板中无法显示错误提示。

错误分析与修复步骤

1. 表单验证方法命名错误(forms.py)

Django表单的字段验证方法必须遵循clean_<字段名>的命名规则,且获取验证后的数据需用self.cleaned_data而非拼写错误的self.validated_data。

修正后的forms.py:

from django import forms
from .models import Postit

MAX_POST_LENGTH = 240

class PostForm(forms.ModelForm):
    class Meta:
        model = Postit
        fields = ['content']

    def clean_content(self):
        content = self.cleaned_data.get("content")
        if len(content) > MAX_POST_LENGTH:
            raise forms.ValidationError("这条消息太长了")
        return content

2. 视图AJAX请求判断逻辑错误(views.py)

原代码中request.headers.get('X-Requested-With' or "HTTP_X_REQUESTED_WITH")的写法存在逻辑漏洞,or运算符优先级导致只会取第一个常量值。需直接检查X-Requested-With请求头是否为XMLHttpRequest。

修正后的post_create_view函数:

def post_create_view(request, *args, **kwargs):
    form = PostForm(request.POST or None)
    next_url = request.POST.get('next') or None
    if form.is_valid():
        obj = form.save(commit=False)
        obj.save()
        # 正确判断AJAX请求
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse(obj.serialize(), status=201)
        if next_url is not None and url_has_allowed_host_and_scheme(next_url, 'localhost'):
            return redirect(next_url)
        form = PostForm()
    # 处理表单错误
    if form.errors:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse(form.errors, status=400)
    return render(request, 'comp/form.html', context={"form": form})

3. 前端未处理错误响应(模板与JS)

原前端代码仅处理了201成功状态,未处理400错误响应,需添加错误提示区域并完善JS逻辑。

模板中添加错误提示区域:

<form class='form' id='create-post-form' method='POST' action='/create-post'>
    {% csrf_token %}
    <input type='hidden' value="/" name="next"/>
    <textarea required="required" class='form-control' name="content" placeholder="在这里输入消息..."></textarea>
    <!-- 错误提示区域 -->
    {% if form.content.errors %}
        <div class="text-danger mt-2">
            {{ form.content.errors.0 }}
        </div>
    {% endif %}
    <button type='submit' class="btn btn-primary mt-2">发布</button>
</form>

完善前端JS的错误处理逻辑:

function handleCreatePostFormDidSubmit(event) {
    event.preventDefault()
    const myForm = event.target
    const myFormData = new FormData(myForm)
    const url = myForm.getAttribute("action")
    const method = myForm.getAttribute("method")
    const xhr = new XMLHttpRequest()
    const responseType = "json"
    xhr.responseType = responseType
    xhr.open(method, url)
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
    xhr.onload = function() {
        // 清除之前的错误提示
        const existingError = myForm.querySelector('.text-danger');
        if (existingError) existingError.remove();
        
        if (xhr.status === 201) {
            const newPostJson = xhr.response
            const newPostElement = formatPostElement(newPostJson)
            const ogHtml = postElementContainer.innerHTML
            postElementContainer.innerHTML = newPostElement + ogHtml
            myForm.reset()
        } else if (xhr.status === 400) {
            // 显示后端返回的错误信息
            const errors = xhr.response;
            if (errors.content) {
                const errorDiv = document.createElement('div');
                errorDiv.className = 'text-danger mt-2';
                errorDiv.textContent = errors.content[0];
                myForm.querySelector('textarea').insertAdjacentElement('afterend', errorDiv);
            }
        }
    }
    xhr.send(myFormData)  
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:30:45