Removing tmp file after return HttpResponse in django

后端 未结 6 657
长情又很酷
长情又很酷 2020-12-11 03:06

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

wrapper = FileWrapper(file(path))
response = HttpResponse(wrapper, content_type=         


        
相关标签:
6条回答
  • 2020-12-11 03:49

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

    0 讨论(0)
  • 2020-12-11 04:04

    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.

    0 讨论(0)
  • 2020-12-11 04:04

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

    # 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
    
    0 讨论(0)
  • 2020-12-11 04:07

    Mostly, we use periodic cron jobs for this.

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

    See 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/

    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.

    0 讨论(0)
  • 2020-12-11 04:09

    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'
    
    0 讨论(0)
  • 2020-12-11 04:10

    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.

    0 讨论(0)
提交回复
热议问题