2

Possible Duplicate:
How to set file name in response

I store files in MongoDB. To serve a file from Pyramid, I do this:

# view file
def file(request):
    id = ObjectId(request.matchdict['_id'])
    collection = request.matchdict['collection']
    fs = GridFS(db, collection)
    f = fs.get(id)
    filename, ext = os.path.splitext(f.name)
    ext = ext.strip('.')
    if ext in ['pdf','jpg']:
        response = Response(content_type='application/%s' % ext)
    else:
        response = Response(content_type='application/file')
    response.app_iter = FileIter(f)
    return response

Using this method, the filename defaults to the ObjectId string of the file, which isn't pretty and lacks the correct file extension. I've looked in the docs to see how/where I can rename the file inside the Response object, but I can't see it. Any help would be fantastic.

Community
  • 1
  • 1
MFB
  • 19,017
  • 27
  • 72
  • 118

2 Answers2

4

There is no 100% foolproof way to set the filename. It's up to browsers to come up with a filename.

That said, you can use the Content-Disposition header to specify that you want the browser to download the file rather than display it, and you can also suggest a filename for the file to use for that file. It looks like this:

Content-Disposition: attachment; filename="fname.ext"

However, there is no reliable cross-browser way to specify a filename with non-ascii characters. See this stackoverflow question for more details. You also have to be careful to use a quoted-string encoding for the filename; you should construct a filename with all non-ascii characters removed and with " quoted with \".

Now for the Pyramid-specific stuff. Simply add a Content-Disposition header to your response. (Note that application/file is not a valid mime type. Use application/octet-stream as a "generic" bag-of-bytes type.)

# "application/file" is not a valid mime type!
content_subtype = ext if ext in ['jpg','pdf'] else 'octet-stream'

# This replaces non-ascii characters with '?'
# (This assumes f.name is a unicode string)
content_disposition_filename = f.name.encode('ascii', 'replace')

response = Response(content_type="application/%s" % content_subtype,
                    content_disposition='attachment; filename="%s"' 
                      % content_disposition_filename.replace('"','\\"')
           )
Community
  • 1
  • 1
Francis Avila
  • 31,233
  • 6
  • 58
  • 96
3

Looks like you have to set the Content-Disposition header:

response.content_disposition = 'attachment; filename=%s' % filename
Nathan Villaescusa
  • 17,331
  • 4
  • 53
  • 56