Dash如何通过双Dropdown配置回调更新查询数据并解决KeyError报错
错误原因
- 回调输入参数顺序和装饰器中Input的顺序不匹配:装饰器里先声明的是
event-dropdown的value,后声明的是run-dropdown的value,回调函数的参数要和这个顺序完全对应,你现在写反了,会导致取值错误。 - 输出数量不匹配:你只声明了1个Output(
output1的children属性),但函数最后返回了6个值,返回值数量和声明的Output数量不一致,就是触发KeyError: 'outputs_list'的直接原因。 - 不推荐使用全局变量存储回调生成的数据:Dash是多线程多用户运行的,全局变量会被不同用户的操作覆盖,导致数据错乱。如果需要在多个回调间共享查询结果,建议用
dcc.Store组件存储序列化后的中间数据。
正确的回调写法
如果你需要把下拉框的值用于数据查询,同时把查询结果用于更新图表、显示文本,推荐修改方案如下:
- 先在layout中添加
dcc.Store组件,用来存储查询得到的中间数据 - 回调的Output数量和返回值数量保持完全一致
- 回调参数顺序和Input的顺序一一对应
修改后的完整代码示例
import dash from dash import dcc, html, Input, Output, State app = dash.Dash(__name__) app.layout = html.Div([ dcc.Dropdown( id='event-dropdown', options=[ {'label': '2021 test', 'value': '12345'}, {'label': '2021 test 2', 'value': '78901'}, ], value = '12345', # 注意初始值要在options的value列表里,不然会取空 searchable=False, style={"width": "40%", "padding-left": "75px", "padding-top": "5px","padding-bottom": "5px","text-align": "center"} ), dcc.Dropdown( id='run-dropdown', options=[ {'label': 'Practice 1', 'value': 'Practice 1'}, {'label': 'Practice 2', 'value': 'Practice 2'}, ], value = 'Practice 1', searchable=False, style={"width": "40%", "padding-left": "75px", "padding-top": "5px","padding-bottom": "5px","text-align": "center"} ), dcc.Graph(id='lapTime-graph',style={'width': '100%', 'height': '900px'}), dcc.Interval( id='interval-component', interval=5*1000, # 5秒刷新一次 n_intervals=0 ), html.Div(id='output1'), # 添加Store组件存储中间数据 dcc.Store(id='cached-data') ]) # 第一个回调:监听下拉框和定时器,查询数据后缓存到Store,同时更新output1 @app.callback( [Output('output1', 'children'), Output('cached-data', 'data')], [Input('event-dropdown', 'value'), Input('run-dropdown', 'value'), Input('interval-component', 'n_intervals')] ) def query_data(event_value, run_value, n): # 参数顺序和上面Input的顺序完全对应,直接拿来用就行 # 这里写你的数据查询逻辑,用event_value和run_value作为查询条件 D = {} # 替换为你的实际查询结果 tab = [] color_box = [] Lap = [] color_tab = [] text = "查询完成,当前选择赛事:{},场次:{}".format(event_value, run_value) # 把要共享的中间数据打包成字典,序列化后存到Store cached_data = { "D": D, "tab": tab, "color_box": color_box, "Lap": Lap, "color_tab": color_tab } # 返回值数量和Output数量一致,第一个返回值对应output1的children,第二个对应cached-data的data return text, cached_data # 第二个回调:从Store取缓存的数据,更新图表 @app.callback( Output('lapTime-graph', 'figure'), Input('cached-data', 'data') ) def update_graph(cached_data): if not cached_data: return dash.no_update # 从缓存里取你需要的数据绘图 D = cached_data["D"] Lap = cached_data["Lap"] # 替换为你的实际绘图逻辑,返回figure对象 fig = { "data": [{"x": Lap, "y": [d.get("lap_time") for d in D], "type": "line"}], "layout": {"title": "圈速统计"} } return fig if __name__ == '__main__': app.run_server(debug=True)
如果不需要多回调共享数据,只是在同一个回调里完成查询+绘图,也可以直接把图表的Output加到第一个回调里,不用加Store组件,只要返回值数量和Output声明数量对应上即可。
内容的提问来源于stack exchange,提问作者MaxB
相关产品推荐
相关产品推荐

