基于jQuery实现Django多文件上传:选中文件列表展示与预上传删除
问题原因
你维护的fileList数组仅用于前端展示,原生<input type="file">的files属性是只读的,无法直接修改。表单提交时,浏览器会自动上传该input中的所有原始文件,不会识别你在页面上删除的操作。
解决方案
自己维护要上传的文件列表,在表单提交时通过FormData对象收集列表中的文件,用AJAX提交到后端,代替原生表单的自动提交逻辑。
修改后的HTML代码(添加表单结构)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"> </script> <form id="upload-form" method="post" enctype="multipart/form-data"> {% csrf_token %} <!-- Django必填的CSRF令牌 --> <div> <input type="file" name="Filename" class="form-control" multiple="" maxlength="255" id="id_Filename"> </div> <div class="block-file-selection"> <p>Selected files:</p> <div id="fileselect"></div> </div> <button type="submit">上传文件</button> </form>
修改后的JavaScript代码(重构提交逻辑)
var fileInput = document.getElementById('id_Filename'); var fileListDisplay = document.getElementById('fileselect'); var uploadForm = document.getElementById('upload-form'); var fileList = []; // 渲染文件列表 function renderFileList() { fileListDisplay.innerHTML = ''; fileList.forEach(function(file, index) { var fileDisplayEl = document.createElement('p'); fileDisplayEl.innerHTML = `${file.name} <button data-index="${index}" class='deletfile'>X</button>`; fileListDisplay.appendChild(fileDisplayEl); }); } // 处理文件选择(追加模式,可重复选择文件) fileInput.addEventListener('change', function(evnt) { for (var i = 0; i < fileInput.files.length; i++) { fileList.push(fileInput.files[i]); } renderFileList(); // 清空input,允许重复选择相同文件 fileInput.value = ''; }); // 删除文件并重新渲染列表 $(document).on('click', '.deletfile', function() { const index = parseInt($(this).attr('data-index'), 10); fileList.splice(index, 1); renderFileList(); }); // 表单提交拦截与AJAX上传 uploadForm.addEventListener('submit', function(e) { e.preventDefault(); // 阻止原生表单提交 // 构造FormData对象 const formData = new FormData(); // 添加CSRF令牌 formData.append('csrfmiddlewaretoken', document.querySelector('[name=csrfmiddlewaretoken]').value); // 添加要上传的文件(name需与Django表单字段名一致) fileList.forEach(function(file) { formData.append('Filename', file); }); // 发送AJAX请求 fetch(uploadForm.action, { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { console.log('上传成功:', data); // 上传成功后清空列表 fileList = []; renderFileList(); }) .catch(error => { console.error('上传失败:', error); }); });
Django后端视图示例
from django.http import JsonResponse def upload_files(request): if request.method == 'POST': # 获取上传的文件列表 files = request.FILES.getlist('Filename') for file in files: # 示例:保存文件到media目录 with open(f'media/{file.name}', 'wb+') as destination: for chunk in file.chunks(): destination.write(chunk) return JsonResponse({'status': 'success', 'message': f'{len(files)}个文件上传成功'}) return JsonResponse({'status': 'error', 'message': '请求方法错误'}, status=400)
额外说明
- 若需要覆盖式选择文件(每次选择都会替换之前的列表),将文件选择事件代码改回:
fileInput.addEventListener('change', function(evnt) { fileList = []; for (var i = 0; i < fileInput.files.length; i++) { fileList.push(fileInput.files[i]); } renderFileList(); }); - 确保Django项目
settings.py中已配置媒体文件的存储路径与访问URL,避免文件保存失败。
内容的提问来源于stack exchange,提问作者Goncalves
相关产品推荐
相关产品推荐

