【问题标题】:Removing tmp file after return HttpResponse in django在 django 中返回 HttpResponse 后删除 tmp 文件
【发布时间】:2010-08-27 08:19:49
【问题描述】:

我正在使用以下 django/python 代码将文件流式传输到浏览器:

wrapper = FileWrapper(file(path))
response = HttpResponse(wrapper, content_type='text/plain')
response['Content-Length'] = os.path.getsize(path)
return response

有没有办法在reponse返回后删除文件?使用回调函数还是什么? 我可以创建一个 cron 来删除所有 tmp 文件,但如果我可以流式传输文件并从同一个请求中删除它们会更整洁。

【问题讨论】:

    标签: python django


    【解决方案1】:

    您可以使用 NamedTemporaryFile:

    from django.core.files.temp import NamedTemporaryFile
    def send_file(request):
        newfile = NamedTemporaryFile(suffix='.txt')
        # save your data to newfile.name
        wrapper = FileWrapper(newfile)
        response = HttpResponse(wrapper, content_type=mime_type)
        response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(modelfile.name)
        response['Content-Length'] = os.path.getsize(modelfile.name)
        return response
    

    一旦 newfile 对象被驱逐,临时文件应该被删除。

    【讨论】:

    • temporary file should be deleted once the newfile object is evicted: 是否有自动删除NamedTemporaryFile 实例的内置机制?
    • 如果我是正确的,一旦对象的所有引用都被销毁,垃圾收集器就会销毁对象。当你退出 send_file 函数时,应该不再有对 newfile 对象的引用,因此它可以在下次 GC 运行时被删除。 NamedTemporaryFile 的析构函数声明: def close(self): if not self.close_call: self.close_call = True self.file.close() self.unlink(self.name) def __del__(self): self.close()
    • fylb,你是对的,但不能保证对象会被垃圾回收并调用它的 del 方法。谁知道垃圾收集器会做什么?最好定期手动清理。
    【解决方案2】:

    供将来参考: 我只是遇到了无法使用临时文件进行下载的情况。 但是我仍然需要在它之后删除它们;所以这就是我的做法(我真的不想依赖 cron 作业或 celery 或 wossnames,它是一个非常小的系统,我希望它保持这种状态)。

    def plug_cleaning_into_stream(stream, filename):
        try:
            closer = getattr(stream, 'close')
            #define a new function that still uses the old one
            def new_closer():
                closer()
                os.remove(filename)
                #any cleaning you need added as well
            #substitute it to the old close() function
            setattr(stream, 'close', new_closer)
        except:
            raise
    

    然后我只是将用于响应的流插入其中。

    def send_file(request, filename):
        with io.open(filename, 'rb') as ready_file:
            plug_cleaning_into_stream(ready_file, filename)
            response = HttpResponse(ready_file.read(), content_type='application/force-download')
            # here all the rest of the heards settings
            # ...
            return response
    

    我知道这既快又脏,但它确实有效。我怀疑它对于每秒有数千个请求的服务器是否会产生生产力,但我的情况并非如此(每分钟最多几十个)。

    编辑:忘记准确地说,我正在处理下载过程中无法放入内存的非常大的文件。所以这就是我使用BufferedReader 的原因(这是io.open() 下面的内容)

    【讨论】:

    • 非常好的先生,谢谢
    【解决方案3】:

    Python 3.7、Django 2.2.5

    from tempfile import NamedTemporaryFile
    from django.http import HttpResponse
    with NamedTemporaryFile(suffix='.csv', mode='r+', encoding='utf8') as f:
        f.write('\uFEFF')  # BOM
        f.write('sth you want')
    
        # ref: https://docs.python.org/3/library/tempfile.html#examples
        f.seek(0)
        data=f.read()
    
        response = HttpResponse(data, content_type="text/plain")
        response['Content-Disposition'] = 'inline; filename=export.csv'
    

    【讨论】:

    • 请为您的答案提供一些解释,并避免发布仅代码答案。
    【解决方案4】:

    一种方法是添加一个视图以删除此文件,并使用异步调用 (XMLHttpRequest) 从客户端 调用它。这种情况的一种变体将涉及从客户端报告成功,以便服务器可以将此文件标记为删除并定期进行清理。

    【讨论】:

    • 对我来说听起来不是一个好主意 - 不需要从客户端到服务器的额外消息。定期清理临时文件要好得多。
    • @loevborg:OP 要求提供替代方案。因此。 I could just make a cron to delete all tmp files, but it would be neater ...
    【解决方案5】:

    这只是使用常规的python方法(非常简单的例子):

    # something generates a file at filepath
    
    from subprocess import Popen
    
    # open file
    with open(filepath, "rb") as fid:
        filedata = fid.read()
    
    # remove the file
    p = Popen("rm %s" % filepath, shell=True)
    
    # make response
    response = HttpResponse(filedata, content-type="text/plain")
    
    return response
    

    【讨论】:

    • 哎呀,有这么多安全漏洞和逃逸问题。
    【解决方案6】:

    大多数情况下,我们为此使用定期 cron 作业。

    Django 已经有一个 cron 作业来清理丢失的会话。你已经在运行它了,对吧?

    http://docs.djangoproject.com/en/dev/topics/http/sessions/#clearing-the-session-table

    您希望在您的应用程序中使用另一个类似此命令的命令来清理旧文件。

    看到这个http://docs.djangoproject.com/en/dev/howto/custom-management-commands/

    另外,你可能不是真的从 Django 发送这个文件。有时,您可以通过在 Apache 使用的目录中创建文件并重定向到 URL 来获得更好的性能,以便 Apache 可以为您提供文件。有时这更快。然而,它并不能更好地处理清理工作。

    【讨论】:

    • 不用重定向,你可以用mod xsendfile和Apache一起使用,然后它是一个请求,你可以控制文件访问。
    猜你喜欢
    • 2019-08-03
    • 2017-08-06
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    • 2012-09-06
    • 2018-10-11
    • 2019-12-31
    • 2011-02-02
    相关资源
    最近更新 更多