hi all,
I want to create a pdf and download this pdf when a button is pressed. I started from this tutorial and modify
a code but the downloaded file cannot be opened.
Upload and Download Files with Plotly Dash
Below is my code:
import base64
import os
from flask import Flask, send_from_directory
# imports for the dashboard creation
import dash
import dash_html_components as html
from dash.dependencies import Input, Output
from dash_extensions.snippets import send_file
from dash_extensions import Download
import numpy as np
from io import BytesIO
# imports for the pdf creation
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import ParagraphStyle
UPLOAD_DIRECTORY = "/files/pdf"
# create folder if not yet created
if not os.path.exists(UPLOAD_DIRECTORY):
os.makedirs(UPLOAD_DIRECTORY)
# Normally, Dash creates its own Flask server internally. By creating our own,
# we can create a route for downloading files directly:
server = Flask(__name__)
app = dash.Dash(server=server)
# Dash Layout
app.layout = html.Div(
[
html.Div([html.Button("Download File", id="button_download_file", n_clicks=0), Download(id="download")]),
],
)
@server.route("/download/<path:path>")
def download(path):
"""Serve a file from the upload directory."""
# Create PDF
#-----------
pdf_buffer = BytesIO()
elements = []
# create style
doc = SimpleDocTemplate(pdf_buffer)
style_title_header = ParagraphStyle(name = 'Title')
# Create Paragraph.
elements.append(Paragraph('hello world !!!', style_title_header))
# create pdf
doc.multiBuild(elements)
# store pdf file
with open(path, "wb") as fp:
# fp.write(base64.decodebytes(pdf_buffer.getvalue()))
fp.write(base64.decodebytes(pdf_buffer.read()))
@app.callback(Output("download", "data"),
[Input("button_download_file", "n_clicks")])
def download_file(n_clicks):
if n_clicks>0:
# pdf file name
pdf_name = 'test.pdf'
# init path of the pdf file
path = os.path.join(UPLOAD_DIRECTORY, pdf_name)
# create pdf and store it
download(path)
return send_file(path, mime_type='application/pdf')
else:
return None
if __name__ == "__main__":
app.run_server(debug=True)