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

如何通过Axios向Django上传文件?切换工具后request.FILES为空求解

用Axios向Django上传文件的正确姿势

你之前遇到的问题核心在于:你传的是Blob URL字符串,而不是实际的文件对象,所以Django没法把它识别成上传文件,自然request.FILES是空的,而字符串会被放到request.POST里。下面我给你一步步讲怎么用react-dropzone + Axios正确上传文件到Django:

一、前端:直接用react-dropzone返回的File对象,构建FormData

react-dropzone的acceptedFiles返回的就是标准的File对象数组,不用转成Blob URL,直接用它来构建FormData就行:

import { useDropzone } from 'react-dropzone';
import axios from 'axios';

function FileUploadComponent() {
  const { getRootProps, getInputProps, acceptedFiles } = useDropzone();

  const handleUpload = async () => {
    if (!acceptedFiles.length) return;

    // 1. 构建FormData,把文件加进去
    const formData = new FormData();
    // 这里的键名`uploaded_file`要和后端接收的字段名一致
    formData.append('uploaded_file', acceptedFiles[0]);
    // 如果需要传其他参数,也可以一起加进去
    // formData.append('description', '这是一张测试图片');

    // 2. 发送Axios请求
    try {
      const res = await axios.post('/api/upload/', formData, {
        headers: {
          // 重点:不要手动设置Content-Type!Axios会自动处理成multipart/form-data并带上正确的boundary
          // 手动设置反而会导致Django解析失败
          'X-CSRFToken': getCsrfToken(), // 带上Django需要的CSRF令牌
        },
      });
      console.log('上传成功!', res.data);
    } catch (err) {
      console.error('上传失败', err);
    }
  };

  // 辅助函数:从cookie里取Django的CSRF令牌
  const getCsrfToken = () => {
    return document.cookie.split('; ').find(row => row.startsWith('csrftoken='))?.split('=')[1];
  };

  return (
    <div {...getRootProps()} style={{ border: '2px dashed #ccc', padding: '20px', cursor: 'pointer' }}>
      <input {...getInputProps()} />
      <p>拖拽文件到这里,或点击选择文件</p>
      {acceptedFiles.length > 0 && (
        <button onClick={handleUpload} style={{ marginTop: '10px' }}>开始上传</button>
      )}
    </div>
  );
}

export default FileUploadComponent;

二、后端:Django接收文件的正确写法

确保你的视图能正确解析multipart/form-data请求,从request.FILES里取文件:

from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.core.files.storage import default_storage

# 生产环境请确保CSRF保护生效,这里如果前端已经传了CSRF令牌,可以去掉csrf_exempt
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
@require_POST
def upload_file_view(request):
    # 从request.FILES里取文件,键名要和前端FormData的键一致
    uploaded_file = request.FILES.get('uploaded_file')
    if not uploaded_file:
        return JsonResponse({'status': 'error', 'msg': '未上传文件'}, status=400)
    
    # 保存文件到Django的媒体目录(需要先在settings里配置MEDIA_ROOT和MEDIA_URL)
    file_path = default_storage.save(uploaded_file.name, uploaded_file)
    
    return JsonResponse({
        'status': 'success',
        'file_name': uploaded_file.name,
        'file_url': f'/media/{file_path}'
    })

三、关键注意事项

  • 不要转Blob URL:直接用react-dropzone返回的File对象,Blob URL是给前端预览用的,不是用来传后端的。
  • 不要手动设置Content-Type:Axios在发送FormData时会自动生成正确的multipart/form-data请求头,包含必要的boundary参数,手动设置会丢失这个参数,导致Django无法解析文件。
  • CSRF令牌要带上:Django默认开启CSRF保护,前端必须在请求头里带上X-CSRFToken,值从cookie里的csrftoken字段取。
  • 配置Django媒体存储:在settings.py里要设置:
    MEDIA_ROOT = BASE_DIR / 'media'
    MEDIA_URL = '/media/'
    
    还要在项目的urls.py里添加媒体文件的路由(仅开发环境用,生产环境用Nginx等托管):
    from django.conf import settings
    from django.conf.urls.static import static
    
    urlpatterns = [
        # 你的其他路由
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    

这样调整后,你就能在Django的request.FILES里拿到上传的文件了,不会再是空的MultiValueDict啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:28:34