Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing tmp file after return HttpResponse in django

Tags:

python

django

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

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.

like image 426
Oli Avatar asked Aug 27 '10 08:08

Oli


2 Answers

You can use a 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.

like image 193
fylb Avatar answered Oct 12 '22 06:10

fylb


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).

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())

like image 21
le-doude Avatar answered Oct 12 '22 06:10

le-doude