在django中返回HttpResponse后删除tmp文件

时间:2021-11-29 20:28:10

I'm using the following django/python code to stream a file to the browser:

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

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

Is there a way to delete the file after the reponse is returned? Using a callback function or something? I could just make a cron to delete all tmp files, but it would be neater if I could stream files and delete them as well from the same request.

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

5 个解决方案

#1


8  

You can use a NamedTemporaryFile:

您可以使用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

temporary file should be deleted once the newfile object is evicted.

驱逐newfile对象后,应删除临时文件。

#2


2  

Mostly, we use periodic cron jobs for this.

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

Django already has one cron job to clean up lost sessions. And you're already running it, right?

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

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

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

You want another command just like this one, in your application, that cleans up old files.

您希望在应用程序中使用另一个命令清除旧文件。

See this http://docs.djangoproject.com/en/dev/howto/custom-management-commands/

见http://docs.djangoproject.com/en/dev/howto/custom-management-commands/

Also, you may not really be sending this file from Django. Sometimes you can get better performance by creating the file in a directory used by Apache and redirecting to a URL so the file can be served by Apache for you. Sometimes this is faster. It doesn't handle the cleanup any better, however.

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

#3


2  

This is just using the regular python approach (very simple example):

这只是使用常规的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

#4


1  

For future references: I just had the case in which I couldn't use temp files for downloads. But I still needed to delete them after it; so here is how I did it (I really didn't want to rely on cron jobs or celery or wossnames, its a very small system and I wanted it to stay that way).

对于将来的参考:我只是遇到了无法使用临时文件进行下载的情况。但我还是需要在它之后删除它们;所以这就是我如何做到的(我真的不想依赖cron工作或芹菜或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

and then I just took the stream used for the response and plugged into it.

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

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

I know this is quick and dirty but it works. I doubt it would be productive for a server with thousands of requests a second, but that's not my case here (max a few dozens a minute).

我知道这很快又脏,但它确实有效。我怀疑对于每秒有数千个请求的服务器来说效率会很高,但这不是我的情况(每分钟最多几十个)。

EDIT: Forgot to precise that I was dealing with very very big files that could not fit in memory during the download. So that is why I am using a BufferedReader (which is what is underneath io.open())

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

#5


0  

One way would be to add a view to delete this file and call it from the client side using an asynchronous call (XMLHttpRequest). A variant of this would involve reporting back from the client on success so that the server can mark this file for deletion and have a periodic job clean it up.

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

#1


8  

You can use a NamedTemporaryFile:

您可以使用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

temporary file should be deleted once the newfile object is evicted.

驱逐newfile对象后,应删除临时文件。

#2


2  

Mostly, we use periodic cron jobs for this.

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

Django already has one cron job to clean up lost sessions. And you're already running it, right?

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

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

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

You want another command just like this one, in your application, that cleans up old files.

您希望在应用程序中使用另一个命令清除旧文件。

See this http://docs.djangoproject.com/en/dev/howto/custom-management-commands/

见http://docs.djangoproject.com/en/dev/howto/custom-management-commands/

Also, you may not really be sending this file from Django. Sometimes you can get better performance by creating the file in a directory used by Apache and redirecting to a URL so the file can be served by Apache for you. Sometimes this is faster. It doesn't handle the cleanup any better, however.

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

#3


2  

This is just using the regular python approach (very simple example):

这只是使用常规的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

#4


1  

For future references: I just had the case in which I couldn't use temp files for downloads. But I still needed to delete them after it; so here is how I did it (I really didn't want to rely on cron jobs or celery or wossnames, its a very small system and I wanted it to stay that way).

对于将来的参考:我只是遇到了无法使用临时文件进行下载的情况。但我还是需要在它之后删除它们;所以这就是我如何做到的(我真的不想依赖cron工作或芹菜或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

and then I just took the stream used for the response and plugged into it.

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

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

I know this is quick and dirty but it works. I doubt it would be productive for a server with thousands of requests a second, but that's not my case here (max a few dozens a minute).

我知道这很快又脏,但它确实有效。我怀疑对于每秒有数千个请求的服务器来说效率会很高,但这不是我的情况(每分钟最多几十个)。

EDIT: Forgot to precise that I was dealing with very very big files that could not fit in memory during the download. So that is why I am using a BufferedReader (which is what is underneath io.open())

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

#5


0  

One way would be to add a view to delete this file and call it from the client side using an asynchronous call (XMLHttpRequest). A variant of this would involve reporting back from the client on success so that the server can mark this file for deletion and have a periodic job clean it up.

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