下载作为字节流生成的 PDF 文件的 Dash 扩展问题

问题描述

我有一个 Dash 应用程序,用户可以在其中与应用程序进行交互,并且将使用 FPDF 生成 PDF。我正在尝试使用 Dash-extensions 包和下载选项来转发要下载的 PDF,但出现错误

我有这个功能生成PDF:

def makeReport(info):
    return create_pdf(info)
def create_pdf(info):
    pdf = CustomPDF(format='letter')
    for i,beam in enumerate(info):
        pdf.addPage(info[i],i)

    data = pdf.output(dest='S').encode('latin-1')
    
    return data

然后是下载按钮相关代码

@app.callback(Output("download","data"),[Input("download_btn","n_clicks")],prevent_initial_call=True)
def sendPDF(n_clicks):
    firstName,lastName,mrn = nameParser(patient)
    fileName = lastName + ',' + firstName + ' Cutout Factor Calc.pdf'
    return send_bytes(makeReport(info),fileName)

def downloadButton():
    return html.Div([html.Hr(),html.Button("Download Report",id="download_btn"),Download(id="download")])

我点击按钮时得到的错误是:

enter image description here

解决方法

send_bytes 实用程序函数需要将字节写入 BytesIO 对象的函数作为第一个参数,但是您传递给它的是一个字节字符串,因此您需要编写一个小的包装函数。这是一个演示如何完成的小示例,

import dash
import dash_html_components as html
from dash.dependencies import Output,Input
from dash_extensions import Download
from dash_extensions.snippets import send_bytes
from fpdf import FPDF

# Create example app.
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([html.Button("Download PDF",id="btn"),Download(id="download")])


def create_pdf(n_nlicks):
    pdf = FPDF()
    pdf.add_page()
    pdf.set_font('Arial','B',16)
    pdf.cell(40,10,f'Hello World! (n_clicks is {n_nlicks})')
    return pdf


@app.callback(Output("download","data"),[Input("btn","n_clicks")])
def generate_xlsx(n_nlicks):
    def write_pdf(bytes_io):
        pdf = create_pdf(n_nlicks)  # pass argument to PDF creation here
        bytes_io.write(pdf.output(dest='S').encode('latin-1'))

    return send_bytes(write_pdf,"some_name.pdf")


if __name__ == '__main__':
    app.run_server()