简体   繁体   English

dash_table.DataTable 持久性与导航链接不兼容

[英]dash_table.DataTable persistence not compatible with navlinks

I'm trying to preserve values in a dash_table.DataTable after switching between apps in an multi page Dash app.在多页 Dash 应用程序中的应用程序之间切换后,我试图在dash_table.DataTable中保留值。 I've tried with both navlinks (example code below), pages (dash 2.5) and tabs .我已经尝试过使用navlinks (下面的示例代码)、 pages (破折号 2.5)和tabs I want to do this using the persistence argument instead of dcc.Store , and with navlinks/pages instead of tabs .我想使用 persistence 参数而不是dcc.Storenavlinks/pages而不是tabs来做到这一点。

It seems refreshing the page overrides the persistence keyword, even when set to 'session' or 'local', as using tabs fixes this issue (tabs does not refresh page).即使设置为“会话”或“本地”,刷新页面似乎也会覆盖持久性关键字,因为使用选项卡可以解决此问题(选项卡不会刷新页面)。 I've also tried dcc.Location with refresh=False without success.我也试过dcc.Locationrefresh=False没有成功。 I've made a small example code to display my issue.我制作了一个小示例代码来显示我的问题。 From my print statements you can also observe the data beeing reset to 'None' after switching between links/pages.从我的打印语句中,您还可以观察到在链接/页面之间切换后数据被重置为'None'

import pandas as pd
import numpy as np
from dash import Dash, callback, html, dcc, dash_table, Input, Output, dash_table, callback_context as ctx
import dash_bootstrap_components as dbc


df = pd.DataFrame({'test1':np.zeros(3), 'test2':np.zeros(3)})
def get_data():
    return df

app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP], suppress_callback_exceptions= True)
app.layout = dbc.Container([
    dcc.Location(id = 'url', refresh = False),
    dbc.Row(
        dbc.Navbar(
            dbc.Nav(children=[
                dbc.NavItem(dbc.NavLink("Main", active='exact', external_link=False, href='/'), id = 'main'),
                dbc.NavItem(dbc.NavLink("A link", active = 'exact', external_link=False, href="/link"), id = 'alink')
            ])
        )
    ),
    html.Div(id = 'link')
])
    
main = html.Div([
            dbc.Row(
                dbc.Col([
                    dbc.Button("test1 +1", id='btn1', className="me-2", n_clicks = 0),
                    dbc.Button("test2 +1", id='btn2', className="me-2", n_clicks = 0)
                ])
            ),
            dbc.Row([
                dbc.Col(
                    dash_table.DataTable(columns = [{'name': x, 'id':x} for x in get_data().columns],
                                         id = 'table',
                                         persistence = True, 
                                         persisted_props = ['data'],
                                         persistence_type = 'session')
                )
            ])
    ])

@app.callback(
    Output('link', 'children'),
    Input('url', 'pathname')
)
def render_page(path):
    print(path)
    if path != '/':
        layout = html.Div(
            dbc.Row(
                html.H5(path)
            )
        )
    else:
        layout = main
    return layout

@app.callback(
    Output('table', 'data'),
    [
     Input('table', 'data'),
     Input("btn1", "n_clicks"),
     Input("btn2", "n_clicks")
    ]
)
def render_table(data,b1,b2):
    print("Data: ", data)
    if data == None:
        return get_data().to_dict('records')
    
    df = pd.DataFrame(data)
    button_id = ctx.triggered[0]["prop_id"].split(".")[0]
    
    if button_id == 'btn1':
        df['test1'] += 1
    elif button_id == 'btn2':
        df['test2'] += 1
    return df.to_dict('records')

app.run_server()

Every time that pathname triggers the first callback and directs the app to the main page, your DataTable is reseted as the df defined in the beggining of the code.每次该pathname触发第一个回调并将应用程序定向到主页时,您的 DataTable 都会重置为代码开头定义的df That's why simply setting the table persistence doesn't help, you're creating it from zero each time.这就是为什么简单地设置表持久性没有帮助,您每次都是从零开始创建它。

If you don't want to use dcc.Store, you need to create your table only once and use pathname triggering for deciding whether you show the table or not.如果您不想使用 dcc.Store,您只需创建一次表并使用pathname触发来决定是否显示该表。 That's what I did with your code, I defined the table in the main layout, and when url is not in the main page, a {'display': 'none'} argument is passed for the table parent div.这就是我对您的代码所做的,我在主布局中定义了表格,当url不在主页中时,为表格父 div 传递了一个{'display': 'none'}参数。

import pandas as pd
import numpy as np
from dash import Dash, callback, html, dcc, dash_table, Input, Output, dash_table, callback_context as ctx
import dash_bootstrap_components as dbc


df = pd.DataFrame({'test1':np.zeros(3), 'test2':np.zeros(3)})
def get_data():
    return df

app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP], suppress_callback_exceptions= True)
app.layout = dbc.Container([
    dcc.Location(id = 'url', refresh = False),
    dbc.Row(
        dbc.Navbar(
            dbc.Nav(children=[
                dbc.NavItem(dbc.NavLink("Main", active='exact', external_link=False, href='/'), id = 'main'),
                dbc.NavItem(dbc.NavLink("A link", active = 'exact', external_link=False, href="/link"), id = 'alink')
            ])
        )
    ),
    html.Div(id = 'link'),
    
    html.Div(id = 'table_div', children = [
            dbc.Row(
                dbc.Col([
                    dbc.Button("test1 +1", id='btn1', className="me-2", n_clicks = 0),
                    dbc.Button("test2 +1", id='btn2', className="me-2", n_clicks = 0)
                ])
            ),
            dbc.Row([
                dbc.Col(
                    dash_table.DataTable(columns = [{'name': x, 'id':x} for x in get_data().columns],
                                         id = 'table',
                                         persistence = True, 
                                         persisted_props = ['data'],
                                         persistence_type = 'session')
                )
            ])
    ])
])

@app.callback(
    Output('link', 'children'),
    Output('link', 'style'),
    Output('table_div', 'style'),
    Input('url', 'pathname')
)
def render_page(path):
    print(path)
    if path != '/':
        layout = html.Div(
            dbc.Row(
                html.H5(path)
            )
        )
        return layout, {'display': ''}, {'display': 'none'}
    else:
        # layout = main
        return [], {'display': 'none'}, {'display': ''}

@app.callback(
    Output('table', 'data'),
    [
     Input('table', 'data'),
     Input("btn1", "n_clicks"),
     Input("btn2", "n_clicks")
    ]
)
def render_table(data,b1,b2):
    print("Data: ", data)
    if data == None:
        return get_data().to_dict('records')
    
    df = pd.DataFrame(data)
    button_id = ctx.triggered[0]["prop_id"].split(".")[0]
    
    if button_id == 'btn1':
        df['test1'] += 1
    elif button_id == 'btn2':
        df['test2'] += 1
    return df.to_dict('records')

app.run_server()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM