CSV/Excel file download/output not unique to each user in different instances

Currently, I have a dashboard that allows users to export queried data in xlsx/csv format but the file generated is stuck with data that is first queried by the first user. If another user queries his/her own data and tries to export, he/she would open the downloaded file and see the data queried by the first user in another instance.

I believe this is due the global variable “queried_df” shown below in my code snippet. Is there a better way to share/send data from the callback to the server route export?

Any other suggestions are appreciated, thank you!

@app.callback(
    Output('tables', 'children'),
    [Input("bom_1", "value"),
     Input("bom_2", "value"),
     Input("org_1", "value"),
     Input("org_2", "value"),
     Input("level", "value"),
     Input('button', 'n_clicks')]
)
def update_tables(bom_1, bom_2, org_1, org_2, level, n_clicks):

    global queried_df

    if n_clicks == 0:
        return dash.no_update

    queried_df = bc.compare(bom_1, org_1, bom_2, org_2, level)

    # perform other actions

    return table


@app.server.route('/export/')
def download_excel():
    strIO = io.BytesIO()
    writer = pd.ExcelWriter(strIO, engine="xlsxwriter")
    left = queried_df[0]
    left.to_excel(writer, sheet_name='Sheet1', startrow=1)
   
    excel_data = strIO.getvalue()
    strIO.seek(0)

    return send_file(strIO, attachment_filename='test.xlsx', as_attachment=True)
1 Like

I guess the simplest solution would be to create a route, which serves files from a folder. You could then save a file with a unique name, e.g. a md5 hash of the data, to that folder from within the callback context. Finally, to enable the download, create a link to the file. The link should be updated by the update_tables callback.

With this approach, every user will be able to download their own data. However, note that all data will be in principle be visible to all users (if they can guess the link). This might be a concern from a security perspective depending on the nature of the data.

thank you for your response, it definitely could work but I found a simpler fix to my issue!

Turns out, send_file() would send the file held in cache. specifying cache_timeout=0 tells it to hold for 0 seconds. So, the solution would be:

return send_file(filename, as_attachment=True, cache_timeout=0)
1 Like