You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dash应用中内存生成并下载PDF文件

问题:Dash应用中实现内存生成PDF并直接供用户下载

我开发了一个Dash应用,希望支持用户下载PDF报告。目前通过pdfkit和jinja实现了本地功能,但需要将文件保存到服务器后再供下载,用户可能对此有顾虑,因此希望仅在内存中处理临时文件(客户端侧)。以下是我的代码,请问有没有更优实现方式?

from dash import Dash, dcc, html, Input, Output
import pdfkit
import jinja2


# Set up sample pdf with pdfkit and jinja based on this tutorial: https://www.youtube.com/watch?v=1IYtkkEOuoU

my_name = "Frank "
item1 = "TV"
today_date = "2022"

context = {'my_name': my_name,
           'item1': item1,
           'today_date': today_date}

template_loader = jinja2.FileSystemLoader('./')
template_env = jinja2.Environment(loader=template_loader)

html_template = 'my-basic-template.html'
template = template_env.get_template(html_template)
output = template.render(context)

# downloaded wkhtmltopdf locally:
path_wkhtmltopdf = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'
config = pdfkit.configuration(wkhtmltopdf=path_wkhtmltopdf)
output_pdf = 'pdf_generated.pdf'
pdfkit.from_string(output, output_pdf, configuration=config)


# Make Dash app
app = Dash(__name__)

app.layout = html.Div([
    html.Button("Download pdf", id="btn-download-pdf"),
    dcc.Download(id="download-pdf")
])


@app.callback(
    Output("download-pdf", "data"),
    Input("btn-download-pdf", "n_clicks"),
    prevent_initial_call=True,
)
def func(n_clicks):
    pdf = pdfkit.from_string(output, configuration=config)
    print(output)
    return dcc.send_file("pdf_generated.pdf", "test_pdf.pdf")


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

优化实现方案

核心思路是完全在内存中生成PDF字节流,直接传给客户端下载,避免服务器写入文件,具体优化如下:

优化后的代码

from dash import Dash, dcc, html, Input, Output
import pdfkit
import jinja2

# 初始化wkhtmltopdf配置(全局只执行一次)
path_wkhtmltopdf = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'
config = pdfkit.configuration(wkhtmltopdf=path_wkhtmltopdf)

# 初始化Jinja2模板环境(全局只执行一次)
template_env = jinja2.Environment(loader=jinja2.FileSystemLoader('./'))

# 创建Dash应用
app = Dash(__name__)

app.layout = html.Div([
    html.Button("Download pdf", id="btn-download-pdf"),
    dcc.Download(id="download-pdf")
])

@app.callback(
    Output("download-pdf", "data"),
    Input("btn-download-pdf", "n_clicks"),
    prevent_initial_call=True,
)
def generate_and_download_pdf(n_clicks):
    # 动态生成上下文数据(可替换为用户输入/数据库查询等动态内容)
    context = {
        'my_name': "Frank",
        'item1': "TV",
        'today_date': "2022"
    }
    
    # 渲染HTML模板
    template = template_env.get_template('my-basic-template.html')
    html_content = template.render(context)
    
    # 在内存中生成PDF字节流(第二个参数传False,不生成本地文件)
    pdf_bytes = pdfkit.from_string(html_content, False, configuration=config)
    
    # 直接返回二进制数据供客户端下载
    return dcc.send_bytes(pdf_bytes, filename="test_pdf.pdf")

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

关键优化点

  1. 内存生成PDF:调用pdfkit.from_string时第二个参数传False,方法会直接返回PDF的二进制字节流,完全跳过服务器文件写入步骤。
  2. 使用dcc.send_bytes:Dash的send_bytes组件支持直接发送二进制数据,无需依赖服务器本地文件,实现纯内存流转。
  3. 逻辑模块化:将模板渲染、PDF生成逻辑封装到回调函数内,方便后续扩展为动态数据(比如根据用户输入生成个性化PDF)。
  4. 清理冗余代码:移除全局范围内生成本地PDF文件的代码,减少不必要的IO操作。

内容的提问来源于stack exchange,提问作者NRVA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 02:30:58