在Django中返回HttpResponse后删除临时文件
我正在使用以下的django/python代码将一个文件传输到浏览器:
wrapper = FileWrapper(file(path))
response = HttpResponse(wrapper, content_type='text/plain')
response['Content-Length'] = os.path.getsize(path)
return response
有没有办法在响应返回后删除这个文件呢?可以用回调函数之类的方式吗?我可以设置一个定时任务来删除所有临时文件,但如果能在同一个请求中既传输文件又删除文件,那样会更整洁。
7 个回答
通常,我们会使用定期的cron任务来处理这个问题。
Django已经有一个定期任务,用来清理那些失效的会话。你应该已经在运行这个任务了,对吧?
你可以查看这个链接了解更多信息: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使用的目录中创建文件,然后通过重定向到一个网址,让Apache来为你提供这个文件,会有更好的性能。这种方式有时会更快。不过,它在清理方面并没有更好的效果。
为了以后参考: 我遇到了一种情况,就是无法使用临时文件来下载。 但我还是需要在下载后删除这些文件,所以我就这样做了(我真的不想依赖定时任务或者其他复杂的东西,这个系统很小,我希望它保持简单)。
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()
背后的实现)。
你可以使用一个命名的临时文件:
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
这个临时文件在新的文件对象被移除后会自动删除。