Plotly Dash多页面间数据传递问题求助(含Store组件报错)
Plotly Dash多页面数据传递(Store组件报错)解决方案
核心问题分析
报错"A nonexistent object was used as an "Input""的本质是:回调引用了当前页面未加载的组件(比如Store仅放在某单个页面,切换页面后组件被销毁),或是Store组件未被注册到全局布局中,导致其他页面无法访问。
分步解决方案
1. 全局注册Store组件
将dcc.Store放在应用的顶层布局里,确保所有页面都能访问到这个存储容器。示例代码:
import dash from dash import dcc, html from dash.page_registry import registry app = dash.Dash(__name__, use_pages=True) # 全局Store,存储跨页面的选择值,初始化为空字典 app.layout = html.Div([ dcc.Store(id='global-store', data={'page1_value': None, 'page2_value': None}), dash.page_container # 用于渲染各个子页面的容器 ]) if __name__ == '__main__': app.run_server(debug=True)
2. 页面1:将下拉选择值存入全局Store
在页面1的布局中添加下拉框,通过回调把选中值写入全局Store:
# pages/page1.py from dash import html, dcc, Input, Output, State, callback layout = html.Div([ dcc.Dropdown( id='page1-dropdown', options=[{'label': f'选项{i}', 'value': f'val{i}'} for i in range(1, 4)], placeholder='选择页面1的值' ), dcc.Link('前往页面2', href='/page2') ]) @callback( Output('global-store', 'data'), Input('page1-dropdown', 'value'), State('global-store', 'data'), prevent_initial_call=False ) def update_store_page1(selected_val, store_data): # 更新Store中page1对应的值 store_data['page1_value'] = selected_val return store_data
3. 页面2:读取Store值过滤数据,同时存入自身选择值
页面2先从全局Store读取页面1的选择值,用于过滤数据并生成自身下拉选项,再把自己的选中值写入Store:
# pages/page2.py from dash import html, dcc, Input, Output, callback, State import pandas as pd # 示例业务数据 df = pd.DataFrame({ 'page1_val': ['val1', 'val1', 'val2', 'val3'], 'page2_val': ['a', 'b', 'a', 'c'], 'data': [10, 20, 30, 40] }) layout = html.Div([ html.Div(id='page2-filtered-result'), dcc.Dropdown(id='page2-dropdown', placeholder='选择页面2的值'), dcc.Link('前往页面3', href='/page3') ]) # 回调1:根据页面1的选择值更新页面2的下拉选项 @callback( Output('page2-dropdown', 'options'), Input('global-store', 'data') ) def update_page2_options(store_data): page1_val = store_data.get('page1_value') if not page1_val: return [] # 过滤出对应页面1值的page2选项 filtered_options = df[df['page1_val'] == page1_val]['page2_val'].unique() return [{'label': val, 'value': val} for val in filtered_options] # 回调2:将页面2的选择值存入全局Store @callback( Output('global-store', 'data'), Input('page2-dropdown', 'value'), State('global-store', 'data'), prevent_initial_call=False ) def update_store_page2(selected_val, store_data): store_data['page2_value'] = selected_val return store_data # 回调3:展示基于页面1值过滤后的原始数据 @callback( Output('page2-filtered-result', 'children'), Input('global-store', 'data') ) def display_page2_data(store_data): page1_val = store_data.get('page1_value') if not page1_val: return '请先在页面1完成选择' filtered_df = df[df['page1_val'] == page1_val] # 用表格展示数据 return html.Table([ html.Thead(html.Tr([html.Th(col) for col in filtered_df.columns])), html.Tbody([ html.Tr([html.Td(filtered_df.iloc[i][col]) for col in filtered_df.columns]) for i in range(len(filtered_df)) ]) ])
4. 页面3:读取两个值完成最终过滤
页面3从全局Store获取页面1和页面2的选择值,执行双重过滤并展示结果:
# pages/page3.py from dash import html, Input, Output, callback import pandas as pd df = pd.DataFrame({ 'page1_val': ['val1', 'val1', 'val2', 'val3'], 'page2_val': ['a', 'b', 'a', 'c'], 'data': [10, 20, 30, 40] }) layout = html.Div([ html.Div(id='page3-final-result') ]) @callback( Output('page3-final-result', 'children'), Input('global-store', 'data') ) def display_final_data(store_data): page1_val = store_data.get('page1_value') page2_val = store_data.get('page2_value') if not page1_val or not page2_val: return '请先完成页面1和页面2的选择' # 双重过滤数据 filtered_df = df[(df['page1_val'] == page1_val) & (df['page2_val'] == page2_val)] if filtered_df.empty: return '没有匹配的数据' return html.Table([ html.Thead(html.Tr([html.Th(col) for col in filtered_df.columns])), html.Tbody([ html.Tr([html.Td(filtered_df.iloc[i][col]) for col in filtered_df.columns]) for i in range(len(filtered_df)) ]) ])
关键注意事项
- 所有跨页面回调依赖的
dcc.Store必须放在全局布局中,不能仅放在单个页面里,否则切换页面后组件会被DOM销毁,回调找不到输入源。 - 使用
prevent_initial_call=False确保页面加载时能正确初始化Store数据,避免空值导致的逻辑异常。 - 跨页面回调的输入/输出只能是全局组件(比如全局Store),不能引用其他页面的局部组件——未加载页面的组件不在当前DOM中,会触发"nonexistent object"错误。
内容的提问来源于stack exchange,提问作者Philipp
相关产品推荐
相关产品推荐

