Search code examples
pythonhtmlcsvflaskpythonanywhere

'Download simulation data' link on html using flask app


I am reading user inputs and sending them for processing. After processing, the results are displayed. Along with the results I want a link on webpage to be able to download the data as a csv file. My function to process inputs looks as follows.

@app.route('/process', methods=['POST'])
def process_data():
    # create csv_file
    return render_template("results.html", data=csv_file)

results.html has following line.

<p><a href="{{ url_for('download', filename=data) }}"> <large>Download simulation data </large></a></p>

This link is correctly displayed on the webpage. My function to download the data looks as follows.

@app.route('/download/<filename>')
def download(filename):
    response = make_response(filename)
    response.headers["Content-Disposition"] = "attachment; filename=Simulation.csv"
    response.headers["Content-Type"] = "text/csv"
    return response

Clicking the download link, I get '414 Request-URI Too Large'.

Is there a better solution for passing data from flask to html to flask again? I can see that my entire data are appended to url, can I somehow avoid that? Is it possible to directly pass response while rendering results.html and make it downloadable?

UPDATE

I learnt that putting data in url is a bad idea. Instead I can use dataurl by encoding the data and then use dataurl for csv in href tag of html.

buffer = StringIO()
dataframe.to_csv(buffer, index=False)
buffer.seek(0)
data_str = base64.b64encode(buffer.getvalue().encode('utf8')).decode('ascii')
url = "data:text/csv; base64,{}".format(data_str)

html looks like as follows.

<a download="SSW_Simulation.csv" href="{{ data_url }}">download</a>

However this solution does not work in internet explorer I guess because urls for data are not supported. Should I be saving the csv file somewhere and pass that filename to html? so that when prompted, I can fetch it from the temporary location and download using make_response? I would prefer not to save the file to the disk.


Solution

  • Handling the data in javascript solved the problem as suggested by @Jeronimo. json string was passed to html page.

    import json
    
    @app.route('/process', methods=['POST'])
    def process_data():
        # create csv_file
        data = json.dumps(csv_file)
        return render_template("results.html", data=data)
    

    Javascript suggested in this answer was added to html and along with download button.

    <button onclick="download({{ data }}, 'myfile.csv', 'text/csv')">download data</button>