Загрузка динамически сгенерированных файлов из приложения Dash / Flask - PullRequest
0 голосов
/ 30 января 2019

Я попытался создать минимальный пример приложения Dash, которое иллюстрирует проблему динамического создания файла, который затем можно загрузить с помощью кнопки загрузки.

Если вы запустите этот пример, вы увидите текстовую область, в которую можно ввести текст.Нажатие на кнопку «Ввод» сохранит текст в файл и создаст кнопку загрузки для файла.

enter image description here

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 кажется неправильным, потому что нажатие на кнопку просто перенаправляет на страницу индекса.Что нужно будет сделать, чтобы это заработало?

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Поскольку Dash построен на Flask, колба не может найти URI для сгенерированного текстового файла.

Решение заключается в добавлении маршрутов фляги для перенаправления для загрузки ресурсов. Существуетпростой пример в официальном репозитории plotly dash, https://github.com/plotly/dash-recipes/blob/master/dash-download-file-link-server.py

Измененный код ниже решает вашу проблему

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каталог, он также будет работать.

Дополнительная информация о статическом каталоге фляги: 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
0 голосов
/ 01 февраля 2019

Решение здесь:

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)
...