Python 从Dash/Flask应用程序下载动态生成的文件

Python 从Dash/Flask应用程序下载动态生成的文件,python,flask,plotly-dash,Python,Flask,Plotly Dash,我试图构建一个Dash应用程序的最小示例,该示例演示了动态生成一个文件的问题,该文件可以通过下载按钮下载 如果运行此示例,您将看到一个可以输入文本的文本区域。单击“回车”按钮将文本存储到文件中,并为文件创建下载按钮 但是,生成的URI似乎不正确,因为单击按钮只会重定向到索引页面。需要什么才能使其工作?解决方案如下: import uuid import dash from dash.dependencies import Input, Output, State import flask f

我试图构建一个Dash应用程序的最小示例,该示例演示了动态生成一个文件的问题,该文件可以通过下载按钮下载

如果运行此示例,您将看到一个可以输入文本的文本区域。单击“回车”按钮将文本存储到文件中,并为文件创建下载按钮

但是,生成的URI似乎不正确,因为单击按钮只会重定向到索引页面。需要什么才能使其工作?

解决方案如下:

import uuid

import dash
from dash.dependencies import Input, Output, State
import flask
from flask.helpers import send_file

import dash_core_components as dcc
import dash_html_components as html

stylesheets = [
    "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css", # Bulma
]

server = flask.Flask('app')

# create app
app = dash.Dash(
    __name__,
    external_stylesheets=stylesheets, 
    server=server                       # <-- do not forget this line
)

# (...) your code here

@server.route("/downloadable/<path>")
def download_file (path = None):
    return send_file("downloadable/" + path, as_attachment=True)
导入uuid
导入破折号
从dash.dependencies导入输入、输出和状态
进口烧瓶
从flask.helpers导入发送文件
将仪表板核心组件作为dcc导入
将dash_html_组件导入为html
样式表=[
"https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css“,#布尔马
]
服务器=flask.flask('app')
#创建应用程序
app=dash.dash(
__姓名,
外部样式表=样式表,

server=server#由于Dash是在flash上构建的,flash无法找到生成的文本文件的URI

解决方案是添加要重定向的flask路由以下载资源, 官方plotly dash存储库中有一个简单的示例,

下面修改的代码解决了您的问题

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

import uuid
import os
import flask
stylesheets = [
    "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css", # Bulma
]

# create app
app = dash.Dash(
    __name__,
    external_stylesheets=stylesheets
)


app.layout = html.Div(
    className="section",
    children=[
        dcc.Textarea(
            id="text-area",
            className="textarea",
            placeholder='Enter a value...',
            style={'width': '300px'}
        ),
        html.Button(
            id="enter-button",
            className="button is-large is-outlined",
            children=["enter"]
        ),
        html.Div(
            id="download-area",
            className="block",
            children=[]
        )
    ]
)

def build_download_button(uri):
    """Generates a download button for the resource"""
    button = html.Form(
        action=uri,
        method="get",
        children=[
            html.Button(
                className="button",
                type="submit",
                children=[
                    "download"
                ]
            )
        ]
    )
    return button

@app.callback(
    Output("download-area", "children"),
    [
        Input("enter-button", "n_clicks")
    ],
    [
        State("text-area", "value")
    ]
)
def show_download_button(n_clicks, text):
    if text == None:
        return
    # turn text area content into file
    filename = f"{uuid.uuid1()}.txt"
    path = f"downloadable/{filename}"
    with open(path, "w") as file:
        file.write(text)
    uri = path
    return [build_download_button(uri)]

@app.server.route('/downloadable/<path:path>')
def serve_static(path):
    root_dir = os.getcwd()
    return flask.send_from_directory(
        os.path.join(root_dir, 'downloadable'), path
    )

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

使用Dash 1.20.0,您现在有了一个用于动态、基于用户的下载的
dcc.Download
组件。它不需要创建自定义按钮、
uuid
flask.send_file

导入破折号
将仪表板核心组件作为dcc导入
将dash_html_组件导入为html
从dash.dependencies导入输入、输出和状态
导入uuid
样式表=[
"https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css“,#布尔马
]
#创建应用程序
app=dash.dash(
__姓名,
外部样式表=样式表
)
app.layout=html.Div(
className=“节”,
孩子们=[
文本区(
id=“文本区域”,
className=“textarea”,
占位符=“输入值…”,
样式={'width':'300px'}
),
按钮(“输入”,id=“btn_txt”),
dcc.下载(id=“下载文本”)
]
)
@app.callback(
输出(“下载文本”、“数据”),
输入(“btn_txt”,“n_点击”),
状态(“文本区域”、“值”),
阻止\u初始\u调用=真,
)
def创建下载文件(n_单击,文本):
filename=“file.txt”
#或者:
#filename=f“{uuid.uuid1()}.txt”
返回dict(内容=文本,文件名=文件名)
你能解释一下语法“”吗?为什么是2,为什么是:?
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

import uuid
import os
import flask
stylesheets = [
    "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css", # Bulma
]

# create app
app = dash.Dash(
    __name__,
    external_stylesheets=stylesheets
)


app.layout = html.Div(
    className="section",
    children=[
        dcc.Textarea(
            id="text-area",
            className="textarea",
            placeholder='Enter a value...',
            style={'width': '300px'}
        ),
        html.Button(
            id="enter-button",
            className="button is-large is-outlined",
            children=["enter"]
        ),
        html.Div(
            id="download-area",
            className="block",
            children=[]
        )
    ]
)

def build_download_button(uri):
    """Generates a download button for the resource"""
    button = html.Form(
        action=uri,
        method="get",
        children=[
            html.Button(
                className="button",
                type="submit",
                children=[
                    "download"
                ]
            )
        ]
    )
    return button

@app.callback(
    Output("download-area", "children"),
    [
        Input("enter-button", "n_clicks")
    ],
    [
        State("text-area", "value")
    ]
)
def show_download_button(n_clicks, text):
    if text == None:
        return
    # turn text area content into file
    filename = f"{uuid.uuid1()}.txt"
    path = f"downloadable/{filename}"
    with open(path, "w") as file:
        file.write(text)
    uri = path
    return [build_download_button(uri)]

@app.server.route('/downloadable/<path:path>')
def serve_static(path):
    root_dir = os.getcwd()
    return flask.send_from_directory(
        os.path.join(root_dir, 'downloadable'), path
    )

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

def show_download_button(n_clicks, text):
    if text == None:
        return
    filename = f"{uuid.uuid1()}.txt"
    path = f"static/{filename}"      # =====> here change the name of the direcotry to point to the static directory
    with open(path, "w") as file:
        file.write(text)
    uri = path
    return [build_download_button(uri)]

#your code