There is a small web application - there you can upload a file for processing via a button, then it is processed and the report on its processing is first presented to the dataframe, then converted to csv and then uploaded to a specific directory.
At the moment, we have implemented the conversion of the dataframe to csv and uploading it to a specific directory.
table_for_export.to_csv(r'path\file_name.csv', sep=';', index = False)
I need to make it so that after downloading the file, a button appears and the processed file can be downloaded to the folder a user can choose.
How to implement this? The plotly dash layout is written at the beginning of the application. I don’t know how to update it and how to make an export button selectable for the entire folder.
To have the user select where they can download the file, the easiest is to simulate a download link in the browser. This is done by creating a Blob in javascript and letting the user “download” this. The quotes are because the data is actually already in the user’s browser, they are just saving it to disk. Unfortunately dash doesn’t yet have a component to do this, so we have to use a little javascript…
What we do here is convert the csv file to base64 and then make a URL with the base64 string as the contents (a technique for storing data in a url). Then we make that URL the href of an html.A component (a hyperlink). You could just put text in the children field of the html.A, but in that case the user could press download even if the href doesn’t contain any data. So your idea to generate the download button is good to prevent that. For that you simply need to make a callback that puts a button the the html.A's children
app.layout = html.Div([
html.A(
id="download",
download="file_name.csv",
className="tooltip",
),
dcc.Store("csv-store")
...
])
def download_csv(table_for_export):
# assuming table_for_export is a pandas data frame
csvbytes = io.BytesIO()
# write the csv file to bytes in memory
table_for_export.to_csv(csvbytes, sep=';', index = False)
# convert to base64 so it can be stored in a dcc.Store (dcc.Store can only
# hold JSON compatible data like printable strings)
csvb64 = base64.b64encode(csvbytes.getvalue()).decode()
return csvb64
@app.callback
update_csv_store_data(
Output("csv-store","data"),
[...] # whatever inputs create the csv
):
... # create the csv
return download_csv(...)
# set the download url to the contents of the csv-store (so they can be
# downloaded from the browser's memory)
app.clientside_callback(
"""
function(the_store_data) {
let s = JSON.stringify(the_store_data);
let b = new Blob([s],{type: 'text/plain'});
let url = URL.createObjectURL(b);
return url;
}
""",
Output("download", "href"),
[Input("csv-store", "data")],
)
@app.callback(
Output('download','children'),
[Input('download','href')]
)
def update_download_children(_): # we probably won't use the href
# fill the children with a download button
return html.Button(id='download-button')
You can also take a look at a full example here (but for a different application)