Django项目中file input的change事件异常问题排查与解决
经@CodeThing的评论提醒,问题出在页面上存在另一个相同表单。这一情况并不明显:遇到该问题的Django开发者,请检查模板中的{% include %}标签,因为另一个包含同名元素的表单位于同一页面的模态框中。JS和Django都不会抛出相关错误,仅查看模板难以发现,需通过浏览器检查工具搜索才能找到。
核心原则:若遇到此类问题,使用检查工具查找是否存在其他相同id的元素,若有则移除,代码即可正常运行。
- 我有两个输入框:(1) 'file-input'文件输入框,(2) 'text-input'文本输入框
- 希望监听'file-input'的'change'事件(即成功选择文件时),并在事件触发时将'text-input'的值设置为所选文件名。
- 使用
addEventListener绑定'change'事件时,事件无法触发 - 使用输入框的'onchange'属性时,事件可触发,但仍无法获取文件列表
这是一个Django项目,前端使用Bootstrap 5(无JQuery)。我尽可能使用Django Crispy Forms,但已将其从该模板中移除(排查是否因此导致问题,但并非如此)。
我知道这本该很简单。我查看了许多类似帖子,并搭建了一个可正常运行的测试HTML脚本,确认思路无误,代码如下:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> </head> <body> <input type="file" name="file" id="file-input" accept=".mp3,.mp4,.mpeg,.mpga,.m4a,.wav,.webm"> <input type="text" name="text" id="text-input"> <script> const fileInput = document.getElementById("file-input"); const textInput = document.getElementById("text-input"); console.log(fileInput); console.log(textInput); fileInput.addEventListener('change', () => { console.log('change registered'); if (fileInput.files.length > 0) { console.log(fileInput.files); console.log(fileInput.files[0].name); textInput.value = fileInput.files[0].name; } }); </script> </body> </html>
该测试脚本输出符合预期,运行正常:
- input id="file-input" type="file" name="file" accept=".mp3,.mp4,.mpeg,.mpga,.m4a,.wav,.webm"
- input id="text-input" type="text" name="text"
- change registered
- FileList [ File ]
- interview.mp4*
我的Django项目模板已尽可能复刻测试脚本的结构,相关代码如下:
<form id="file-form" method="post" enctype="multipart/form-data"> {% csrf_token %} <div class="my-4 px-1"> <input type="file" name="file" id="file-input" accept=".mp3,.mp4,.mpeg,.mpga,.m4a,.wav,.webm"> </div> <div class="my-3 px-1"> <input type="text" name="text" id="text-input"> </div> <button type="submit" class="btn btn-add"> Transcribe </button> <script> const fileInput = document.getElementById("file-input"); const textInput = document.getElementById("text-input"); console.log(fileInput); console.log(textInput); fileInput.addEventListener('change', () => { console.log('change registered'); if (fileInput.files.length > 0) { console.log(fileInput.files); console.log(fileInput.files[0].name); textInput.value = fileInput.files[0].name; } }); </script> </form>
但该代码输出异常,change事件未触发!
即仅输出以下内容:
- input id="file-input" class="form-control form-control-file" type="file" name="file" required=""
- input id="text-input" type="text" name="text"
- 无其他输出
我尝试使用输入框的'onchange'属性修复,事件虽可触发,但fileInput.files仍为空列表,无法解决问题。
我查阅了一些Stack Overflow答案,但它们仅在测试脚本中有效,无法解决我的问题。
我是否遗漏了什么?为何测试脚本正常运行,但Django版本却不行?脚本确实在运行(可正确打印两个输入框);已排除Django Crispy Forms的影响;移除form和csrf_input后问题仍存在。我对此感到十分困惑!
恳请各位提供帮助!
内容的提问来源于stack exchange,提问作者KingRanTheMan

