You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Streamlit-AgGrid嵌套网格修改DataFrame后无法显示更新数据求助

解决嵌套AgGrid网格不更新数据的问题

我仔细看了你的代码和问题描述,核心问题出在数据类型不一致AgGrid组件未强制刷新这两点上,勾选第二个复选框的异常也和这两个原因直接相关。下面是具体的分析和修复方案:

问题根源拆解

  1. DataFrame列类型不匹配

    • 初始化时,你通过pd.json_normalize(x)instrumentData列转成了DataFrame类型
    • 但在_update_instruments_and_injections_df里,直接把_injection_json(Python列表)赋值给该列,导致列内数据类型从DataFrame变成了列表,AgGrid的渲染器无法识别这种类型突变,自然不会更新显示。
  2. 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

火山引擎 最新活动