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

如何在Django中直接将文件上传至Cloudinary、S3等第三方存储服务器

解决Django大文件上传耗时问题:自定义UploadHandler直接对接存储

我之前也碰到过一模一样的大文件上传瓶颈——Django默认的上传流程会先把文件暂存到内存或者磁盘,再交给Storage保存,大文件的时候这个中间步骤简直是噩梦。自定义UploadHandler是完美的解决方案,核心思路就是在文件流式上传的过程中,直接把收到的字节块写入目标存储,完全跳过本地暂存环节。

下面是具体的实现步骤和注意事项:

1. 编写自定义UploadHandler

创建一个继承自FileUploadHandler的类,重写关键方法来接管文件上传的数据流处理:

# myapp/uploadhandlers.py
from django.core.files.uploadhandler import FileUploadHandler, StopFutureHandlers
from myapp.storage import YourCustomStorage  # 替换成你实际使用的Storage类

class DirectStorageUploadHandler(FileUploadHandler):
    def __init__(self, request=None):
        super().__init__(request)
        self.storage = YourCustomStorage()
        self.target_file = None
        self.file_name = ""

    def new_file(self, field_name, file_name, content_type, content_length, charset=None, content_type_extra=None):
        # 初始化要上传的文件,打开Storage中的写入句柄
        self.file_name = file_name
        self.target_file = self.storage.open(file_name, 'wb')
        # 阻止后续默认handler处理,避免重复操作
        raise StopFutureHandlers()

    def receive_data_chunk(self, raw_data, start):
        # 把收到的每一块字节直接写入Storage
        if self.target_file:
            self.target_file.write(raw_data)
        return None  # 返回None告诉Django我们自己处理了数据,不用缓存

    def file_complete(self, file_size):
        # 上传完成后关闭文件句柄,返回关联到Storage的文件对象
        self.target_file.close()
        # 这样request.FILES里拿到的就是已经在Storage中的文件了
        return self.storage.open(self.file_name, 'rb')

2. 配置并启用自定义Handler

你可以全局配置,也可以仅在特定视图中使用:

全局配置(settings.py)

把自定义Handler放到FILE_UPLOAD_HANDLERS的最前面,确保优先被调用:

FILE_UPLOAD_HANDLERS = [
    'myapp.uploadhandlers.DirectStorageUploadHandler',
    'django.core.files.uploadhandler.MemoryFileUploadHandler',
    'django.core.files.uploadhandler.TemporaryFileUploadHandler',
]

视图级动态配置

如果只需要在特定上传视图中使用,就在视图函数开头覆盖上传处理器:

# views.py
from django.http import HttpResponse
from django.views.decorators.http import require_POST
from myapp.uploadhandlers import DirectStorageUploadHandler

@require_POST
def large_file_upload(request):
    # 仅当前视图使用自定义上传处理器
    request.upload_handlers = [DirectStorageUploadHandler(request)] + request.upload_handlers
    
    # 后续正常处理request.FILES就行,文件已经直接存在Storage里了
    uploaded_file = request.FILES['file']
    # 这里不需要再调用storage.save()!Handler已经完成了上传操作
    return HttpResponse(f"文件 {uploaded_file.name} 已成功上传到存储")

3. 关键注意事项

  • Storage的流式支持:确保你的Storage类支持流式写入(比如S3的boto3分块上传、本地文件系统都没问题),如果是第三方存储,要确认SDK是否支持边接收边写入。
  • 错误处理:一定要在receive_data_chunk和file_complete里加异常捕获,比如网络中断时要删除Storage里的不完整文件,避免垃圾数据。
  • 进度跟踪(可选):如果需要做上传进度条,可以在receive_data_chunk里累计已上传字节数,再通过某种方式(比如WebSocket)同步给前端。
  • 权限验证:别忘记在Handler或者视图里加权限校验,防止未授权的文件上传。

这么改造之后,大文件上传时完全绕开了Django的本地暂存,直接把数据流怼到目标存储,速度和服务器资源占用都会改善很多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:20:12