【问题标题】:Dash download in-memory generated file on button click: How to give filename?破折号在按钮单击时下载内存中生成的文件:如何给出文件名?
【发布时间】:2020-05-29 09:37:51
【问题描述】:

我通过pd.ExcelWriterBytesIO 为我的Python3.8 dash 应用程序中的点击事件生成一个内存中 Excel 文件。

一切正常。当我下载我的文件时,我收到此弹出消息,询问我是否要继续下载/打开生成的文件。但是,弹出消息显示了这个(我猜是base64 编码的)字符串(或路径?),例如...ydaHdjhgk328AAAAnxsAA== 并在下载后得到一组(随机分配的?)字符作为文件名(例如ZySzsdn1.xlsx)。

我该如何调整它以显示文件名并将其分配给download.xlsx 之类的东西?我的猜测是这与base64 编码的href 有关。

生成excel文件的函数:

def write_product_file():
    output = BytesIO()
    writer = pd.ExcelWriter(output, engine="xlsxwriter")
    upload_df = pd.DataFrame()
    upload_df.to_excel(writer, index=False, sheet_name="sheet1")
    writer.save()
    return output

我的 Dash 应用程序中的按钮:

html.Div(
  id="select-upload-form",
  style={"width": "100%"},
  children=[
    dbc.Button(
      "Download the upload form",
      id="download-excel",
      color="secondary",
      external_link="true",
      target="",
      href="",
    ),
  ],
),

最后是我的回调:

@app.callback(
    [
        Output("download-excel", "href"),
        Output("download-excel", "color"),
        Output("download-excel", "target"),
    ],
    [Input("download-excel", "n_clicks")],
)
def download_template_file(n_clicks):
    if n_clicks:
        excelfile = write_product_file()
        excelfile.seek(0)
        media_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        data = base64.b64encode(excelfile.read()).decode("utf-8")
        href_data = f"data:{media_type};base64,{data}"
        return href_data, "success", href_data,
    else:
        return None, "secondary", None

【问题讨论】:

    标签: python-3.x button download filenames plotly-dash


    【解决方案1】:

    您可以使用 dash-extensions 包中的 Download 组件,

    pip install dash-extensions == 0.0.18
    

    语法更简单,它有一个filename 参数。这是一个小例子,

    import dash
    import dash_html_components as html
    import numpy as np
    import pandas as pd
    
    from dash.dependencies import Output, Input
    from dash_extensions import Download
    from dash_extensions.snippets import send_bytes
    
    # Generate some example data.
    data = np.column_stack((np.arange(10), np.arange(10) * 2))
    df = pd.DataFrame(columns=["a column", "another column"], data=data)
    # Create app.
    app = dash.Dash(prevent_initial_callbacks=True)
    app.layout = html.Div([html.Button("Download xlsx", id="btn"), Download(id="download")])
    
    
    @app.callback(Output("download", "data"), [Input("btn", "n_clicks")])
    def generate_xlsx(n_nlicks):
    
        def to_xlsx(bytes_io):
            xslx_writer = pd.ExcelWriter(bytes_io, engine="xlsxwriter")
            df.to_excel(xslx_writer, index=False, sheet_name="sheet1")
            xslx_writer.save()
    
        return send_bytes(to_xlsx, "some_name.xlsx")
    
    
    if __name__ == '__main__':
        app.run_server()
    

    免责声明:我是 dash-extensions 包的作者。

    【讨论】:

    • 完美运行!
    • 嗨 ehmher,非常感谢这个扩展!这真的帮助了我很多。我在想,如果我的应用确实需要初始回调并且我不想触发这个下载回调,有没有办法做到这一点?
    • 是的,您可以将 prevent_initial_call=True 添加到回调本身。
    • bytes_ioNone?
    • 您能解释一下为什么这个解决方案有效吗? send_bytes 得到一个返回 None 的函数。它如何获取内容? IE。它如何访问 xlsx_writer?
    猜你喜欢
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 2011-02-07
    相关资源
    最近更新 更多