如何多次使用Django的TemporaryUploadedFile对象?
Django临时上传文件找不到问题的解决方案
问题描述
尝试通过TemporaryUploadedFile对象在Django中创建多条记录时,出现错误:
[Errno 2] No such file or directory: '/tmp/tmpoz8_c7i3.upload.jpg'
已尝试重写相关类并设置tempfile.NamedTemporaryFile(delete=False),但问题依旧。
环境信息:
- Django版本:4.1.3
- Python版本:3.8.18
自定义上传处理类代码:
from django.core.files.uploadhandler import FileUploadHandler, TemporaryFileUploadHandler from django.core.files.uploadedfile import UploadedFile import os from django.conf import settings from django.core.files import temp as tempfile class CustomTemporaryFileUploadHandler(TemporaryFileUploadHandler): """ Upload handler that streams data into a temporary file. """ def new_file(self, *args, **kwargs): """ Create the file object to append to as data is coming in. """ super().new_file(*args, **kwargs) self.file = CustomTemporaryUploadedFile( self.file_name, self.content_type, 0, self.charset, self.content_type_extra ) def receive_data_chunk(self, raw_data, start): self.file.write(raw_data) def file_complete(self, file_size): self.file.seek(0) self.file.size = file_size return self.file def upload_interrupted(self): if hasattr(self, "file"): temp_location = self.file.temporary_file_path() try: self.file.close() os.remove(temp_location) except FileNotFoundError: pass class CustomTemporaryUploadedFile(UploadedFile): """ A file uploaded to a temporary location (i.e. stream-to-disk). """ def __init__(self, name, content_type, size, charset, content_type_extra=None): _, ext = os.path.splitext(name) file = tempfile.NamedTemporaryFile( suffix=".upload" + ext, dir=settings.FILE_UPLOAD_TEMP_DIR, delete=False ) super().__init__(file, name, content_type, size, charset, content_type_extra) def temporary_file_path(self): """Return the full path of this file.""" return self.file.name def close(self): try: return self.file.close() except FileNotFoundError: # The file was moved or deleted before the tempfile could unlink # it. Still sets self.file.close_called and calls # self.file.file.close() before the exception. pass
问题原因
- 请求生命周期自动清理:Django默认会在请求结束后清理临时上传文件,即使设置了
delete=False,框架的默认清理逻辑仍可能触发文件删除。 - 临时目录自动清理:默认的
/tmp目录可能被系统定期清理,导致文件在处理多条记录时已被删除。 - 自定义处理类的清理冲突:自定义
UploadHandler的upload_interrupted方法会删除文件,正常流程中可能被意外触发。
解决方案
1. 持久化临时文件
不要直接使用原临时文件路径,而是将文件复制到持久化目录(如媒体目录),再基于复制后的文件创建多条记录:
from django.core.files.storage import default_storage from django.core.files.base import ContentFile # 处理上传文件时执行复制 uploaded_file = request.FILES['your_file_field'] # 复制到持久化目录 persisted_file_path = default_storage.save(f"temp_uploads/{uploaded_file.name}", ContentFile(uploaded_file.read())) # 后续使用persisted_file_path操作多条记录
2. 禁用默认清理逻辑
重写自定义UploadHandler的cleanup方法,跳过Django的默认清理:
class CustomTemporaryFileUploadHandler(TemporaryFileUploadHandler): # ... 保留原有方法 ... def cleanup(self, file_name): # 跳过默认清理,避免删除已设置delete=False的文件 pass
3. 配置稳定的临时文件目录
在settings.py中指定一个不会被系统自动清理的临时目录:
import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) FILE_UPLOAD_TEMP_DIR = os.path.join(BASE_DIR, "custom_temp_uploads")
然后创建目录并设置权限:
mkdir custom_temp_uploads chmod 755 custom_temp_uploads
4. 确保文件操作时序正确
在创建多条记录时,确保文件对象处于打开状态,不要在关闭文件后再访问文件路径。如果必须关闭文件,先完成所有记录的创建操作。
内容的提问来源于stack exchange,提问作者Víctor Silva Luna
相关产品推荐
相关产品推荐

