多页面 Dash 应用程序中的数据持久化

问题描述 投票:0回答:1

我有一个 Dash 应用程序,用户在一个页面

data.py
中添加一些数据,然后可以在另一页面
grid.py
上查看和删除选定的行。用户稍后应该能够返回
data.py
并添加更多数据。

问题:在访问

grid.py
之间数据不会保留。我怎样才能做到这一点?我尝试设置
persistence
属性,但这并没有让我有任何进展。
existing_data
中的
grid.py
始终是
None
。当我使用单页应用程序时,类似的代码可以工作。

这是我的最小可重现示例:

app.py

from dash import html, dcc
import dash

app = dash.Dash(__name__, use_pages=True)

app.layout = html.Div(
    [
        dcc.Store(id="store", data={}),
        html.H1("Multi Page App Demo: Sharing data between pages"),
        html.Div(
            [
                html.Div(
                    dcc.Link(f"{page['name']}", href=page["path"]),
                )
                for page in dash.page_registry.values()
            ]
        ),
        html.Hr(),
        dash.page_container,
    ]
)


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

数据.py

from dash import html, Input, Output, callback, register_page
from dash.exceptions import PreventUpdate
import random

register_page(__name__, path="/")


layout = html.Div(
    [
        html.H3("Data input"),
        html.Button("Add row", id="button_id"),
        html.Br(),
        html.Div(id="my-output"),
    ]
)


@callback(
    [Output("store", "data"), Output("my-output", "children")],
    Input("button_id", "n_clicks"),
    prevent_initial_call=True
)
def add_data(n_clicks):
    if n_clicks:
        new_data = [{"col1": "New row", "col2": random.randint(0, 1000)}]
        return new_data, html.Pre(str(new_data))
    else:
        raise PreventUpdate

grid.py

from dash import html, dash_table, Input, Output, callback, register_page, State


register_page(__name__)


layout = html.Div([
    html.H3("Data tables"),
    dash_table.DataTable(
        id="table",
        row_deletable=True,
        column_selectable="single",
        page_size=5,
        persistence=True,
        persisted_props=[
            "data",
            "columns.name",
            "filter_query",
            "hidden_columns",
            "page_current",
            "selected_columns",
            "selected_rows",
            "sort_by",
        ],
    ),
])


@callback(
    Output("table", "data"),
    Input("store", "data"),
    State("table", "data"),
)
def update(new_data, existing_data):
    if existing_data is not None:
        return existing_data + new_data
    else:
        return new_data
python plotly plotly-dash
1个回答
0
投票

我想出了两种方法:

  1. 共享
    Store
    组件。
  2. 使用 dash_extensions.pages 中的持久组件功能。

为了完整起见,我将分享两者。拥有(2)的一个原因是我不完全理解为什么(1)有效,据我所知它引入了循环依赖。后者应该抛出异常,或者更糟糕的是,导致无限的回调循环,但事实并非如此。这对于

Dash
来说很聪明,但我不能确定它总是有效 - 它没有记录在案。

共享

Store
组件

app.py:

from dash import html, dcc
import dash

app = dash.Dash(__name__, use_pages=True)

app.layout = html.Div(
    [
        dcc.Store(id="store", data=[], storage_type="session"),
        html.H1("Multi Page App Demo: Sharing data between pages"),
        html.Div(
            [
                html.Div(
                    dcc.Link(f"{page['name']}", href=page["path"]),
                )
                for page in dash.page_registry.values()
            ],
        id='navbar'),
        html.Hr(),
        dash.page_container
    ]
)


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

页面/data.py

from dash import html, Input, Output, callback, register_page, State
from dash.exceptions import PreventUpdate
import random

register_page(__name__, path="/")


layout = html.Div(
    [
        html.H3("Data input"),
        html.Button("Add row", id="button_id"),
        html.Br(),
        html.Div(id="my-output"),
    ]
)


@callback(
    [Output("store", "data"), Output("my-output", "children")],
    Input("button_id", "n_clicks"),
    State("store", "data")
)
def add_data(n_clicks, data):
    if n_clicks:
        new_data = [{"col1": "New row", "col2": random.randint(0, 1000)}]
        return data + new_data, html.Pre(str(new_data))
    else:
        raise PreventUpdate

pages/grid.py:

from dash import html, dash_table, Input, Output, callback, register_page


register_page(__name__)


layout = html.Div([
    html.H3("Data tables"),
    dash_table.DataTable(
        id="table",
        data=[{"name": "Test", "label": "Test"}],
        row_deletable=True,
        column_selectable="single",
        page_size=5,
        persistence=True,
        persisted_props=["columns.name", "data"],
    ),
])


@callback(
    Output("table", "data"),
    Input("store", "data"),
)
def add_rows(new_data):
    return new_data

@callback(
    Output("store", "data", allow_duplicate=True),
    Input("table", "data"),
    prevent_initial_call=True
)
def update_back(new_data):
    return new_data

使用

dash_extensions.pages

中的持久组件功能

app.py:

from dash import html, dcc
from dash_extensions.pages import setup_page_components
from pages.components import NAVBAR_ID
import dash

app = dash.Dash(__name__, use_pages=True)

app.layout = html.Div(
    [
        dcc.Store(id="store", data=[], storage_type="session"),
        html.H1("Multi Page App Demo: Sharing data between pages"),
        html.Div(
            [
                html.Div(
                    dcc.Link(f"{page['name']}", href=page["path"]),
                )
                for page in dash.page_registry.values()
            ],
        id=NAVBAR_ID),
        html.Hr(),
        dash.page_container,
        setup_page_components()
    ]
)

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

页面/组件.py

from dash import dash_table

NAVBAR_ID = "navbar"

data_table = dash_table.DataTable(
        id="table",
        row_deletable=True,
        column_selectable="single",
        page_size=5,
        persistence=True,
        persisted_props=[
            "data",
            "columns.name",
        ]
    )

页面/data.py

from dash import html, Input, Output, callback, register_page
from dash.exceptions import PreventUpdate
import random

register_page(__name__, path="/")


layout = html.Div(
    [
        html.H3("Data input"),
        html.Button("Add row", id="button_id"),
        html.Br(),
        html.Div(id="my-output"),
    ]
)


@callback(
    [Output("store", "data"), Output("my-output", "children")],
    Input("button_id", "n_clicks")
)
def add_data(n_clicks):
    if n_clicks:
        new_data = [{"col1": "New row", "col2": random.randint(0, 1000)}]
        return new_data, html.Pre(str(new_data))
    else:
        raise PreventUpdate

页面/grid.py

from dash import html, Input, Output, callback, register_page, State
from pages.components import data_table


register_page(__name__, page_components=[data_table])


layout = html.Div([
    html.H3("Data tables"),
])


@callback(
    Output("table", "data"),
    Input("store", "data"),
    State("table", "data")
)
def add_rows(new_data, old_data):
    if old_data:
        return old_data + new_data
    return new_data
© www.soinside.com 2019 - 2024. All rights reserved.