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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 13:36:30