Streamlit-AgGrid嵌套网格修改DataFrame后无法显示更新数据求助
解决嵌套AgGrid网格不更新数据的问题
我仔细看了你的代码和问题描述,核心问题出在数据类型不一致和AgGrid组件未强制刷新这两点上,勾选第二个复选框的异常也和这两个原因直接相关。下面是具体的分析和修复方案:
问题根源拆解
DataFrame列类型不匹配:
- 初始化时,你通过
pd.json_normalize(x)把instrumentData列转成了DataFrame类型; - 但在
_update_instruments_and_injections_df里,直接把_injection_json(Python列表)赋值给该列,导致列内数据类型从DataFrame变成了列表,AgGrid的渲染器无法识别这种类型突变,自然不会更新显示。
- 初始化时,你通过
AgGrid组件未感知数据变化:
Streamlit的组件渲染依赖状态变化信号,即使你更新了st.session_state里的DataFrame,如果AgGrid组件没有收到“需要重新渲染”的触发信号,它会复用之前的缓存,不会展示新数据。
具体修复步骤
1. 统一instrumentData列的数据类型
修改_update_instruments_and_injections_df函数,确保赋值给instrumentData的是和初始化一致的DataFrame类型:
def _update_instruments_and_injections_df(selected = [], always_update = False): _instruments = st.session_state["instruments_and_injections_df"]["instrument_name"].to_list() for _instrument in _instruments: if _instrument in selected: _injection_json = _get_injection(_instrument) # 把列表转成DataFrame,和初始化时的格式保持一致 _injection_df = pd.json_normalize(_injection_json) _instrument_index = st.session_state["instruments_and_injections_df"].index[st.session_state["instruments_and_injections_df"]['instrument_name']==_instrument].tolist()[0] st.session_state["instruments_and_injections_df"].at[_instrument_index, "instrumentData"] = _injection_df
2. 添加动态Key强制AgGrid刷新
给AgGrid组件添加一个动态的key参数,每当数据更新时改变这个key,让Streamlit重新渲染组件。可以用计数器实现:
- 首先在初始化函数里添加计数器:
def build_initial_instruments_df(): # ... 原代码 ... st.session_state["grid_refresh_counter"] = 0
- 然后在更新数据后递增计数器:
if st.session_state["instruments_grid_response"]['selected_rows'] != []: _selected_instruments = pd.DataFrame(st.session_state["instruments_grid_response"]['selected_rows'])["instrument_name"].to_list() _update_instruments_and_injections_df(selected = _selected_instruments) # 递增计数器,触发AgGrid刷新 st.session_state["grid_refresh_counter"] += 1 else: st.write("No instruments selected")
- 最后给AgGrid组件加上动态key:
st.session_state["instruments_grid_response"] = AgGrid( st.session_state["instruments_and_injections_df"], gridOptions=gridOptions, height=st.session_state["grid_height"], allow_unsafe_jscode=True, enable_enterprise_modules=True, data_return_mode=st.session_state["return_mode_value"], update_mode=st.session_state["update_mode_value"], key=f"instruments_grid_{st.session_state['grid_refresh_counter']}" # 新增动态key )
3. 优化getDetailRowData的JS代码
现在instrumentData是标准DataFrame,转成JSON后是结构化数据,调整JS代码直接使用即可,不需要额外的JSON.parse:
"getDetailRowData": JsCode( """function (params) { params.successCallback(params.data.instrumentData); }""" ).js_code,
额外优化建议
- 避免重复更新:可以记录上次选中的仪器列表,只有当选中列表变化时才调用
_update_instruments_and_injections_df,减少不必要的数据库查询和数据更新; - 处理空数据:当
_get_injection返回空列表时,确保_injection_df是一个空的DataFrame,避免子网格渲染异常。
按照上面的步骤修改后,勾选复选框时,AgGrid应该能正确更新子网格的数据,也不会出现第二个复选框的异常了。
内容的提问来源于stack exchange,提问作者RightmireM




