python - 服务于 Flask 服务器的 Dash 应用程序内部服务器错误 : A name collision occurred between blueprints

标签 python flask web-applications plotly-dash

我正在 Flask 服务器中使用 Dash 应用程序。

这就是我实例化 Flask 服务器的方式:

from flask import Flask, redirect
server = Flask(__name__, template_folder="../frontend/templates",
               instance_relative_config=True)

这是 create_dash_app 函数:

import dash
def create_dash_app(server):

    dash_app = dash.Dash(
    __name__,
    server=server,
    url_base_pathname='/dash/',
    external_stylesheets=['https://codepen.io/chriddyp/pen/bWLwgP.css']
    )

    dash_app.config['suppress_callback_exceptions'] = True

    dash_app.layout = html.H3("Lorem ipsum... ")

    return dash_app.server

在我的一个服务器路由中,我有以下内容:

@server.route('/filter')
def filter_stuff():

    <some code>

    create_dash_app()
    redirect("/dash")

重点是,对于我的用例,用户可能希望查看 dash 应用程序,返回到过滤器路由,应用一些过滤器并检查 dash 应用程序中的更改。 不幸的是,当我这样做时,我得到以下信息:

> AssertionError: A name collision occurred between blueprints
> <flask.blueprints.Blueprint object at 0x11905bcd0> and
> <flask.blueprints.Blueprint object at 0x118acbad0>. Both share the
> same name "_dash_dash_assets". Blueprints that are created on the fly
> need unique names.

鉴于我对 Flask 和 Dash 的经验不多,我想我缺少的是一些微不足道的东西。如果您可能需要其他信息,请告诉我。

编辑:我找到了一个让我感到羞愧的解决方法 第二次编辑:包括一个回调示例

from flask import Flask, redirect
from multiprocessing import Value
counter = Value('i', 0)

server = Flask(__name__, template_folder="../frontend/templates",
               instance_relative_config=True)


@server.route('/filter')
def filter_stuff():
    with counter.get_lock():
        counter.value += 1
        out = counter.value
    <some code>

    dash_address = "/dash"+str(out)+"/"
    create_dash_app(server, dash_address, nodes_cyto, edges_cyto)

    redirect(dash_address)


import dash
from dash_core_components import *
from dash.dependencies import Input, Output
def create_dash_app(server, dash_address, nodes_cyto, edges_cyto):

    dash_app = dash.Dash(
    __name__,
    server=server,
    url_base_pathname=dash_address,
    external_stylesheets=['https://codepen.io/chriddyp/pen/bWLwgP.css']
    )

    dash_app.config['suppress_callback_exceptions'] = True

    dash_app.layout = html.Div([
            cyto.Cytoscape(
                id='cytoscape_net',
                elements=nodes_cyto + edges_cyto,
                zoomingEnabled=True,
                zoom=0.8,
                layout={'name': 'klay'},
                style={'width': '80%', 'height': '700px', 'float': 'left'},
                stylesheet=my_stylesheet 
            ),
        dcc.Tabs([
            dcc.Tab(label='Dettaglio Interazioni',  style=tab_style, selected_style=tab_selected_style, children=[
                dash_table.DataTable(
                    id='edge-table',
                    columns=[],
                    style_header={
                        'backgroundColor': 'rgb(230, 230, 230)',
                        'fontWeight': 'bold'
                    },
                    fixed_rows={'headers': True},
                    style_data = {'whiteSpace': 'normal',
                                  'height': 'auto',
                                    'lineHeight': '15px'},
                    style_data_conditional=[
                        {
                            'if': {'row_index': 'odd'},
                            'backgroundColor': 'rgb(248, 248, 248)'
                        },
                        {
                            'if': {'column_id': 'Info'},
                            'textAlign': 'right'
                        }
                    ],
                    style_cell={
                        'height': 'auto',
                        'minWidth': '180px', 'width': '180px', 'maxWidth': '180px',
                        'whiteSpace': 'normal',
                        'fontSize':14
                    },
                    style_table={'width': '50%',
                                 'overflowY': 'auto',
                                 'overflowX': 'auto'},
                    data=[])
            ])
    init_callbacks(dash_app)
    return dash_app.server

def init_callbacks(app):
    @app.callback([Output('edge-table', 'data'),
               Output('edge-table', 'columns')],
              [Input('cytoscape_net', 'tapEdgeData')])

    def populateEdgeTable(data):
        json_data = json.loads(json.dumps(data, indent=2))

        if data is None:
            return [], []
        dict_data = dict(json_data)

        dict_data_1 = {your_key.replace("_1", ""): dict_data[your_key] for your_key in
                   [j for j in dict_data.keys() if "_1" in j] + ["tipo_interazione"]}
        dict_data_2 = {your_key.replace("_2", ""): dict_data[your_key] for your_key in
                   [j for j in dict_data.keys() if "_2" in j] + ["tipo_interazione"]}

        columns = [{'name': 'Info', 'id': 'Info'},
               {'name': 'Source', 'id': 'Source'},
               {'name': 'Target', 'id': 'Target'}]

        return pd.DataFrame({'Info': list(dict_data_1.keys()),
                         'Source': list(dict_data_1.values()),
                         'Target': list(dict_data_2.values())}).to_dict(orient='records'), columns

如您所见,我每次都使用计数器重定向到新页面。我想知道是否有人会死于阅读此文。

谢谢

最佳答案

虽然 Dash 应用程序可以动态实例化,但根据我的经验,这是一种应该避免的设计模式。关于这个问题中针对的具体用例,我会考虑两个主要途径,

将过滤器与 Dash 应用集成

最简单和连贯的解决方案是将过滤器作为 Dash 应用程序本身的一部分。使用这种方法,可以通过将过滤器值作为 State 参数传递给页面呈现回调来将过滤器应用于其他页面。它们可以直接传递(如果没有太多过滤器)或通过例如聚合一个 Store 组件。这是一个代码片段来说明这个概念,

@app.callback(Output("store", "data"), [Input("filter{}".format(i), "value") for i in range(100)])
def aggregate_filters(*args):
    return list(args)


@app.callback(Output("page", "children"), [Input(...)], [State("store", "data")])
def render_page(*args, filters):
    ...

将过滤器选择传递给 Dash 应用

如果无法将过滤器页面本身移植到 Dash,您可以序列化过滤器选择并将它们传递给 Dash 应用程序。可能是例如通过 URL(如果没有太多选择)或 session 变量。这是后者的草图,

from flask import session, redirect

...

@server.route('/filter')
def filter_stuff():
    # This assignment might happen from JavaScript depending on you app structure
    session["filters"] = ...  
    redirect(dash_address)

...

@app.callback(Output("page", "children"), [Input(...)])
def render_page(*args, filters):
    filters = session["filters"]
    ...

此方法的其他变体包括保存选择服务器端(例如,在文件或内存缓存中,如 Redis),由一个键标识,例如一个 uuid,然后通过 URL 传递给 Dash 应用程序。

关于您目前使用的 hack,除了不太漂亮之外,我担心它会耗尽服务器资源,因为每次过滤器选择更改时您都在有效地创建一个新的 Dash 应用程序。

关于python - 服务于 Flask 服务器的 Dash 应用程序内部服务器错误 : A name collision occurred between blueprints,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61921054/

相关文章:

javascript - 是否可以为我的 sqlite 数据库生成一个随机且唯一的 5 位数 ID?

java - Jetty 曾经用于生产部署吗?

web-services - 如何模拟一个 'down'的网站?

python - 在两个不同的 fixture 上运行相同的测试

python - gunicorn 不在 supervisord 下工作(但自己工作)

python - 计算图像python中的角度

python - 如何在flask-restful中自定义响应内容类型?

c# - 在 Web 应用程序中使用 C# 显示图像

python - pip freeze > requirements.txt - 权限被 sudo 拒绝? (heroku-flask 教程)

python - 如何将 Unicode 组合到 Python 2 输出中?