使用Vanilla JS+AJAX提交Django表单需点击两次提交按钮问题求解
问题根源排查
核心原因是CKEditor编辑器没有在表单提交前实时将内容同步到对应的原生textarea元素:
- 第一次点击提交时,
FormData读取的是未更新的原始textarea值,提交到Django后form.is_valid()校验失败(content字段为空或者不符合规则),所以视图直接返回了200状态的表单渲染结果,没有存入数据库。 - 第一次提交操作触发了CKEditor的内容同步逻辑,第二次提交时textarea已经写入了正确的内容,校验通过就返回201创建成功。
解决方法
1. 提交前手动同步CKEditor内容到textarea
修改你的JS提交事件逻辑,在构造FormData之前先触发CKEditor的内容同步:
const handlePostSubmit = function(e){ e.preventDefault() // 新增:同步所有CKEditor实例的内容到对应的textarea for (let instance in CKEDITOR.instances) { CKEDITOR.instances[instance].updateElement(); } const myForm = e.target const myFormData = new FormData(myForm) // 后续原有逻辑保持不变 const url = myForm.getAttribute("action") const method = myForm.getAttribute("method") const xhr = new XMLHttpRequest() xhr.open(method, url) xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") xhr.onload = function() { const serverResponse = xhr.response console.log(serverResponse, xhr.status) const postsEl = document.getElementById("posts") loadPosts(postsEl) } xhr.send(myFormData) }
2. 可选优化:增加表单校验失败的提示
你可以在xhr.onload里加状态判断,方便后续排查问题:
xhr.onload = function() { console.log(xhr.response, xhr.status) if(xhr.status === 201) { loadPosts(document.getElementById("posts")) // 可选:提交成功后清空表单 postCreateFormEl.reset() } else { // 校验失败时输出错误信息,方便调试 console.log("表单提交失败,请检查字段是否符合要求") } }
额外说明
你代码里设置的HTTP_X_REQUESTED_WITH请求头是多余的,Django识别AJAX请求只需要X-Requested-With: XMLHttpRequest即可,保留后者就行。
内容的提问来源于stack exchange,提问作者Josie
相关产品推荐
相关产品推荐

