Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django return file over HttpResponse - file is not served correctly

Tags:

I want to return some files in a HttpResponse and I'm using the following function. The file that is returned always has a filesize of 1kb and I do not know why. I can open the file, but it seems that it is not served correctly. Thus I wanted to know how one can return files with django/python over a HttpResponse.

@login_required
def serve_upload_files(request, file_url):
    import os.path
    import mimetypes
    mimetypes.init()

    try:
        file_path = settings.UPLOAD_LOCATION + '/' + file_url
        fsock = open(file_path,"r")
        #file = fsock.read()
        #fsock = open(file_path,"r").read()
        file_name = os.path.basename(file_path)
        file_size = os.path.getsize(file_path)
        print "file size is: " + str(file_size)
        mime_type_guess = mimetypes.guess_type(file_name)
        if mime_type_guess is not None:
            response = HttpResponse(fsock, mimetype=mime_type_guess[0])
        response['Content-Disposition'] = 'attachment; filename=' + file_name            
    except IOError:
        response = HttpResponseNotFound()
    return response

Edit: The bug is actually not a bug ;-)

This solution is working in production on an apache server, thus the source is ok.

While writing this question I tested it local with the django development server and was wondering why it does not work. A friend of mine told me that this issue could arise if the mime types are not set in the server. But he was not sure if this is the problem. But one thing for sure.. it has something to do with the server.

like image 579
Thomas Kremmel Avatar asked Mar 29 '10 13:03

Thomas Kremmel


2 Answers

Could it be that the file contains some non-ascii characters that render ok in production but not in development?

Try reading the file as binary:

fsock = open(file_path,"rb")
like image 107
alves Avatar answered Sep 24 '22 13:09

alves


Try passing the fsock iterator as a parameter to HttpResponse(), rather than to its write() method which I think expects a string.

response = HttpResponse(fsock, mimetype=...)

See http://docs.djangoproject.com/en/dev/ref/request-response/#passing-iterators

Also, I'm not sure you want to call close on your file before returning response. Having played around with this in the shell (I've not tried this in an actual Django view), it seems that the response doesn't access the file until the response itself is read. Trying to read a HttpResponse created using a file that is now closed results in a ValueError: I/O operation on closed file.

So, you might want to leave fsock open, and let the garbage collector deal with it after the response is read.

like image 40
Ben James Avatar answered Sep 22 '22 13:09

Ben James