Flask应用下载动态生成的文件

Flask应用下载动态生成的文件

本文介绍了从Dash/Flask应用下载动态生成的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I tried to build a minimal example of a Dash app that illustrates the problem of dynamically generating a file that can then be downloaded via a download button.

如果运行此示例,您将看到一个文本区域,可以在其中输入文本.单击输入"按钮,会将文本存储到文件中,并为该文件创建一个下载按钮.

If you run this example, you will see a text area where text can be entered. A click on the "enter" button will store the text to a file and create a download button for the file.

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

import uuid

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):
    # 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)]


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

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

However, the generated URI seems to be incorrect, because a click on the button just redirects to the index page. What would be needed to make it work?

推荐答案

由于Dash是基于Flask构建的,因此flask无法找到所生成文本文件的URI.

Since Dash is built upon Flask, flask is not able to locate the URI for the text file that is generated.

解决方案是添加烧瓶路由以重定向以下载资源,在官方的情节破折号存储库中有一个简单的示例, https://github.com/plotly /dash-recipes/blob/master/dash-download-file-link-server.py

The solution is to add the flask routes to redirect to download the resources,There is a simple example in the official plotly dash repository,https://github.com/plotly/dash-recipes/blob/master/dash-download-file-link-server.py

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

The modified code below solves your problem

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)

或者,您可以使用static目录而不是downloadable目录,它也将正常工作.

Alternatively, you can use the static directory instead of the downloadable directory, It will work as well.

有关flask静态目录的更多信息: http://flask.pocoo.org/docs/1.0/tutorial/static/

More information on flask static directory:http://flask.pocoo.org/docs/1.0/tutorial/static/

这是代码段,

#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

这篇关于从Dash/Flask应用下载动态生成的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 08:00