[CherryPy]: force download

365 views
Skip to first unread message

Andrés Chandía

unread,
Apr 11, 2011, 2:32:57 PM4/11/11
to cherrypy-users
Hi there, I'm a complete newbe in cherrypy, anyway I've been able to
create my first cherrypy web succesfully, but I need to add the
possibility of dowloading a static file, always the same one. I've
been reading and trying to do it by myself but no success, so I claim
for help... the file I need to download is generated by a second
python script. I know I have to create a download class, I don't know
exactly how, nor how to call the class (or
function). normal link displays it at the browser because it is a text
file, that's why i need to force download.
The code:
{{{
def Parser(template, params):
for var in params:
expr = r"%"+var+"%"
template = re.sub(expr, params[var], template)
return template
class indexpage(object):
def index(self):
return "NMT"
index.exposed = True
class helloworld(object):
indexpage = indexpage()
_cp_config = {'tools.staticdir.on': True,
'tools.staticdir.root': '/path/to/files',
'tools.staticdir.dir': '',
}
# maybe here I should define the download class, something like this?
(not sure)
class Download:
def index(self, filepath):
return serve_file(filepath, "application/x-download",
"attachment")
index.exposed = True
#
def index(self):
return """ here the html code with textarea """
def NMT(self, contents=None):
if not contents:
return "<a href=\"http://localhost:8080/\">Try
again</a>"
else:
# here a lot of regexps like this one
contents = re.sub(r'(C|c)([^h])', r"\1h
\2" ,contents)
# open (or create) the destination file
with open("nmt.txt","w") as fileout:
fileout.write(contents)
# the resulting html page
return """the downloading link: <a href="nmt.txt">download</
a>(or somthing similar)"""
NMT.exposed = True
index.exposed = True
cherrypy.config.update({'server.socket_host': '127.0.0.1',
'server.socket_port': 8090,
})
cherrypy.quickstart(helloworld())
}}}

Thanks for all your help

David Bolen

unread,
Apr 11, 2011, 3:43:18 PM4/11/11
to cherryp...@googlegroups.com
Andrés Chandía <and...@chandia.net> writes:

> (...) normal link displays it at the browser because it is a text


> file, that's why i need to force download.

> (...)

To force a browser to offer to download a file rather than processing it
internally, set the Content-Disposition header in the response and indicate
that the page is an attachment. You can also supply a file name to use by
default in the same header.

So for example, if you had a CSV file, somewhere in your request processing
code you could include:

cherrypy.response.headers['content-type'] = 'text/csv'
cherrypy.response.headers['content-disposition'] = 'attachment; filename=xxx'

which would force a browser to prompt to download the file. Adjust type
and filename as needed.

In my experience, historically I had mixed results with browser
handling of the specified filename, so I typically arrange to have the
referencing URL end in a similar name, since that seems to be what
some browsers defaulted to suggesting as the save name. This was a
while back, so not sure how true it still holds, but I've just kept
using the pattern.

-- David

Robert Brewer

unread,
Apr 11, 2011, 11:35:13 PM4/11/11
to cherryp...@googlegroups.com
Or use http://docs.cherrypy.org/dev/refman/lib/static.html#cherrypy.lib.static.serve_download which does those headers for you, instead of serve_file.


Robert Brewer
fuma...@aminus.org

> --
> You received this message because you are subscribed to the Google
> Groups "cherrypy-users" group.
> To post to this group, send email to cherryp...@googlegroups.com.
> To unsubscribe from this group, send email to cherrypy-
> users+un...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/cherrypy-users?hl=en.

"Andrés Chandía"

unread,
Apr 13, 2011, 3:50:29 AM4/13/11
to cherryp...@googlegroups.com, David Bolen

Thanks David for your advice, but as I have explained at the message, I'm a total unexpert, so
I've been trying with no success, let me paste the relevant part of the code and what I have
done, so if you can correct me it would be a great help to finally arrive to a good point.

# the resulting html page
��� ��� return
"""

<!-- the html code -->
<!-- the relevant part -->
<form action="download" name="downfile"><input
type="submit" name="downfile" value="download"
/></a></form>

# then the downloading function
��� def download(self, downfile=file):
���
��� if downfile:
��� ��� ���


cherrypy.response.headers['content-type'] = 'text/csv'
���
��� ��� cherrypy.response.headers['content-disposition'] =

'attachment; filename=exemple.txt'
��� download.exposed = True

This gives me the downloading dialog but not getting the file, I mean, when you select
download it downloads a file named exemple.txt, but empty, so I deduce, it creates, out of
something that is not the required file, a file with the given name, but that does not means
it transfers the file exemple.txt

I'm stacked on this.

Thanks again for
your help


El Lun, 11 de Abril de 2011, 21:43, David Bolen escribi�:

-- David


_______________________
������������andr�s
chand�a

P No imprima
innecesariamente. �Cuide el medio ambiente!


David Bolen

unread,
Apr 13, 2011, 5:58:22 AM4/13/11
to cherryp...@googlegroups.com
"Andrés Chandía" <and...@chandia.net> writes:

> This gives me the downloading dialog but not getting the file, I
> mean, when you select download it downloads a file named
> exemple.txt, but empty, so I deduce, it creates, out of something
> that is not the required file, a file with the given name, but that
> does not means it transfers the file exemple.txt

The behavior makes sense, since I don't see anywhere in your sample
code that you actually send the file. Your page handler just returns, so
essentially you are generating an empty result for that URL. My
suggestions for the headers just controls how the browser will handle
the page result, not how you generate the contents.

If, for example, you were to simply add:

return "This is a file"

to the end of your download() method, you'd probably find that string
would then be the contents of example.txt.

However, if you really are just trying to return the contents of a
static file in the filesystem, I'd agree with the other suggestion by
Robert Brewer to use static.serve_download, as it can take care of both
the headers and then transferring the file contents.

In that case, just return the result of calling serve_download on your
static file from within your page handler and it should take care of things,
so for example:

from cherrypy.lib.static import serve_download

def download():
return serve_download(<path-to-file>)

serve_download also accepts an optional "name" parameter to set the
filename, which defaults to the basename of the supplied path.

My suggestion for setting the headers is more appropriate when you are
dynamically generating the content (as is usually the case for me), in
which case after establishing the headers as you have in your sample
download() method, you would then take whatever steps are necessary to
generate the actual data contents as with any other CherryPy page
handler.

-- David

"Andrés Chandía"

unread,
Apr 13, 2011, 10:55:51 AM4/13/11
to cherryp...@googlegroups.com, David Bolen, Robert Brewer

Thanks a lot David and Robert,

finally this code did the trick:

{{{


from cherrypy.lib.static import serve_download
��� def

download(self):
������� ��� return
serve_download('path/to/file/exemple.txt')
��� download.exposed = True
}}}


El Mie, 13 de Abril de 2011, 11:58, David Bolen escribi�:

from cherrypy.lib.static import serve_download

-- David


Reply all
Reply to author
Forward
0 new messages