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

如何多次使用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

问题原因

  1. 请求生命周期自动清理:Django默认会在请求结束后清理临时上传文件,即使设置了delete=False,框架的默认清理逻辑仍可能触发文件删除。
  2. 临时目录自动清理:默认的/tmp目录可能被系统定期清理,导致文件在处理多条记录时已被删除。
  3. 自定义处理类的清理冲突:自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:25:02