Downloading dynamically generated files from a Dash/Flask app Downloading dynamically generated files from a Dash/Flask app flask flask

Downloading dynamically generated files from a Dash/Flask app


Since Dash is built upon Flask, flask is not able to locate the URI for the text file that is generated.

The solution is to add the flask routes to redirect to download the resources,There is a simple example in the official plotly dash repository, https://github.com/plotly/dash-recipes/blob/master/dash-download-file-link-server.py

The modified code below solves your problem

import dashimport dash_core_components as dccimport dash_html_components as htmlfrom dash.dependencies import Input, Output, Stateimport uuidimport osimport flaskstylesheets = [    "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css", # Bulma]# create appapp = dash.Dash(    __name__,    external_stylesheets=stylesheets)app.layout = html.Div(    className="section",    children=[        dcc.Textarea(            id="text-area",            className="textarea",            placeholder='Enter a value...',            style={'width': '300px'}        ),        html.Button(            id="enter-button",            className="button is-large is-outlined",            children=["enter"]        ),        html.Div(            id="download-area",            className="block",            children=[]        )    ])def build_download_button(uri):    """Generates a download button for the resource"""    button = html.Form(        action=uri,        method="get",        children=[            html.Button(                className="button",                type="submit",                children=[                    "download"                ]            )        ]    )    return button@app.callback(    Output("download-area", "children"),    [        Input("enter-button", "n_clicks")    ],    [        State("text-area", "value")    ])def show_download_button(n_clicks, text):    if text == None:        return    # turn text area content into file    filename = f"{uuid.uuid1()}.txt"    path = f"downloadable/{filename}"    with open(path, "w") as file:        file.write(text)    uri = path    return [build_download_button(uri)]@app.server.route('/downloadable/<path:path>')def serve_static(path):    root_dir = os.getcwd()    return flask.send_from_directory(        os.path.join(root_dir, 'downloadable'), path    )if __name__ == '__main__':    app.run_server(debug=True)

Alternatively, you can use the static directory instead of the downloadable directory, It will work as well.

More information on flask static directory:http://flask.pocoo.org/docs/1.0/tutorial/static/

Here is the snippet,

#your codedef show_download_button(n_clicks, text):    if text == None:        return    filename = f"{uuid.uuid1()}.txt"    path = f"static/{filename}"      # =====> here change the name of the direcotry to point to the static directory    with open(path, "w") as file:        file.write(text)    uri = path    return [build_download_button(uri)]#your code


Solution here:

import uuidimport dashfrom dash.dependencies import Input, Output, Stateimport flaskfrom flask.helpers import send_fileimport dash_core_components as dccimport dash_html_components as htmlstylesheets = [    "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css", # Bulma]server = flask.Flask('app')# create appapp = dash.Dash(    __name__,    external_stylesheets=stylesheets,     server=server                       # <-- do not forget this line)# (...) your code here@server.route("/downloadable/<path>")def download_file (path = None):    return send_file("downloadable/" + path, as_attachment=True)


With Dash 1.20.0, you now have a dcc.Download component for dynamic, user-based downloads. It doesn't require creating a custom button, uuid and flask.send_file.

import dashimport dash_core_components as dccimport dash_html_components as htmlfrom dash.dependencies import Input, Output, Stateimport uuidstylesheets = [    "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css", # Bulma]# create appapp = dash.Dash(    __name__,    external_stylesheets=stylesheets)app.layout = html.Div(    className="section",    children=[        dcc.Textarea(            id="text-area",            className="textarea",            placeholder='Enter a value...',            style={'width': '300px'}        ),        html.Button("Enter", id="btn_txt"),         dcc.Download(id="download-text")    ])@app.callback(    Output("download-text", "data"),    Input("btn_txt", "n_clicks"),    State("text-area", "value"),    prevent_initial_call=True,)def create_download_file(n_clicks, text):    filename = "file.txt"    # Alternatively:    # filename = f"{uuid.uuid1()}.txt"    return dict(content=text, filename=filename)