如何在django中提供创建的临时文件

时间:2015-12-13 09:24:35

标签: python django

我有一个远程存储项目,当用户请求他的文件时,django服务器在本地检索并存储文件(用于某些处理)作为临时文件,然后使用mod x-sendfile将其提供给用户。我希望tempfile在提供给用户后肯定会被删除。

在文档中声明NamedTemporaryFile删除参数,如果设置False导致删除文件,之后所有引用都消失了。但是当用户为tempfile提供服务时,它不会被删除。如果我在下载的情况下设置了delete = True,我会得到"在此服务器上找不到请求的URL /ServeSegment/Test.jpg/。"

以下是列出用户文件的视图:

def file_profile(request):
    obj = MainFile.objects.filter(owner=request.user)
    context = {'title': 'welcome',
               'obj': obj
               }
    return render(request, 'ServeSegments.html', context=context)

这是一个视图,它可以检索,临时存储并提供所请求的文件:

def ServeSegment(request, segmentID):    
    if request.method == 'GET':    
        url = 'http://192.168.43.7:8000/foo/'+str(segmentID)
        r = requests.get(url, stream=True)
        if r.status_code == 200:
            with tempfile.NamedTemporaryFile(dir=
        '/tmp/Files', mode='w+b') as f:
                for chunk in r.iter_content(1024):
                    f.write(chunk)        
            response = HttpResponse()
            response['Content-Disposition'] = 'attachment; segmentID={0}'.format(f.name)
            response['X-Sendfile'] = "{0}".format(f.name)
            return response
        else:
            return HttpResponse(str(segmentID))

我想如果我可以设法在语句中返回响应,然后写完最后一个块,它会按照我的意愿工作,但我找不到关于如何确定我们是否在最后一个循环中的解决方案(没有是hackish)。

我该怎么做才能提供tempfile并在之后删除?

3 个答案:

答案 0 :(得分:2)

文件处理程序关闭后,tempfile创建的任何文件都将被删除。在您的情况下,退出with语句时。 delete=False参数会阻止此行为,并将删除更新到应用程序。在<{3}}处理程序发送文件后,可以删除该文件,该文件将在发送响应后取消链接文件。

您的示例对该文件不执行任何操作,因此您可能希望直接使用registering a signalStreamingHttpResponse来流式传输内容。但正如你所说&#34;将文件存储在本地(用于某些处理)&#34; ,我建议在没有创建任何临时文件的情况下进行处理,只能使用流。< / p>

答案 1 :(得分:2)

添加避免使用信号的通用答案(基于Cyrbil&#39;)

import os
import tempfile
from django.http import FileResponse

def my_view(request):
    try:
        tmp = tempfile.NamedTemporaryFile(delete=False)
        with open(tmp.name, 'w') as fi:
            # write to your tempfile, mode may vary
        response = FileResponse(open(tmp.name, 'rb'))
        return response
    finally:
        os.remove(tmp.name)

答案 2 :(得分:0)

一次性文件 该问题的解决方案是不要在NamedTemporaryFile中使用并处理异常。目前,您的文件在读取前已被删除。最后返回

f.seek(0)
return FileResponse(f, as_attachment=True, filename=f.name)

读取完成后,临时文件将关闭,因此将被删除。

非一次性文件

对于偶然发现的人,没有自动处理的文件柄。

从其他答案来看,信号似乎是一个合理的解决方案,但是传递数据需要更改受保护的成员。我不确定将来会如何支持。我还发现,whp的解决方案在当前版本的Django中不起作用。我能想到的最适合未来的版本是猴子修补文件输出,以便在关闭时删除文件。 Django在发送文件结束时关闭了文件句柄,我看不到这一变化。

def my_view(request):
  tmp = tempfile.NamedTemporaryFile(delete=False)

  try:
    # write file tmp (remember to close if re-opening)
    # after write close the file (if not closed)      

    stream_file = open(tmp.name, 'rb')

    # monkey patch the file
    original_close = stream_file.close

    def new_close():
        original_close()
        os.remove(tmp.name)

    stream_file.close = new_close

    # return the result
    return FileResponse(stream_file, as_attachment=True, filename='out.txt')
  except Exception:
      os.remove(output.name)
      raise