Search code examples
python-2.7csvcherrypyexport-to-csv

My csv export download button is broken


I am using cherrypy to run an interactive website and although the python function to generate the CSV seems to be working (if you interact with it directly, my browser downloads it), it does not seem to be giving the user this CSV file when I embed it in a form request:

<form id="export_csv_left" action="/c/flex_export_csv" method="get">
<input type="hidden" name="datakey" value="8TZbmRZ54IL7" >
<button type="button">Export stories and data as CSV</button>
</form>

I'd like there to be a button that says "export CSV" and return the file. That form generates a request to my cherrypy that looks like this:

djotjog.com/c/flex_export_csv?datakey=8TZbmRZ54IL7

The headers inside the cherrypy part are...

csv = make_csv(literal_eval(raw_data), filename)
cherrypy.response.headers['Content-Type'] = "application/x-download"
cherrypy.response.headers['Content-Disposition'] = ('attachment; filename= %s' % (filename,))
return csv

And loading that link in the browser DOES generate the CSV. So what's up with the form stuff?

Here are some potentially relevant javascript console messages I don't really understand:

 Denying load of chrome-extension://ganlifbpkcplnldliibcbegplfmcfigp/scripts/vendor/jquery/jquery.min.map. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension. 

In case that's related.


Solution

  • Your issue has nothing to do with CherryPy per se. Just make sure your form button type attribute is submit and response content-type header is generic application/octet-stream (or text/csv). Like this.

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    
    import cherrypy
    
    
    config = {
      'global' : {
        'server.socket_host' : '127.0.0.1',
        'server.socket_port' : 8080,
        'server.thread_pool' : 4
      }
    }
    
    
    class App:
    
      @cherrypy.expose
      def index(self):
        return '''<!DOCTYPE html>
          <html>
          <body>
            <form action="/gimmefile" method="get">
              <input type="hidden" name="key" value="8TZbmRZ54IL7"/>
              <button type="submit">Export CSV</button>
            </form>
          </body>
          </html>
        '''
    
      @cherrypy.expose
      def gimmefile(self, key):
        cherrypy.response.headers['Content-Type']        = 'application/octet-stream'
        cherrypy.response.headers['Content-Disposition'] = 'attachment; filename=yourfile.csv'
        return 'Your;file;content;and;{0}'.format(key)
    
    
    if __name__ == '__main__':
      cherrypy.quickstart(App(), '/', config)