使用GridUpdateMode.NO_UPDATE获取Streamlit-AgGrid复选框选中行
解决Streamlit AgGrid在NO_UPDATE模式下获取选中行并避免卡顿的方案
核心方案
使用GridUpdateMode.NO_UPDATE禁用自动渲染更新,通过自定义JavaScript在提交按钮点击时主动获取AgGrid的选中行数据,再将数据传递回Python端处理GET请求,全程避免频繁组件重渲染导致的卡顿。
完整代码实现
import streamlit as st from st_aggrid import AgGrid, GridOptionsBuilder, GridUpdateMode import pandas as pd import json import requests # 生成模拟测试数据(2000行20列) def generate_test_data(): data = {f"Col_{i}": range(2000) for i in range(20)} df = pd.DataFrame(data) # 添加唯一ID列,确保AgGrid能准确识别行 df["row_id"] = df.index.astype(str) return df st.title("AgGrid 批量选中提交示例") # 初始化会话状态,存储选中行数据 if "selected_rows" not in st.session_state: st.session_state.selected_rows = [] df = generate_test_data() # 配置AgGrid选项 gb = GridOptionsBuilder.from_dataframe(df) gb.configure_selection("multiple", use_checkbox=True, groupSelectsChildren=True) # 设置行唯一标识,避免排序/过滤后选中行混乱 gb.configure_grid_options(getRowId="params.data.row_id") grid_options = gb.build() # 渲染AgGrid,使用NO_UPDATE模式 grid_response = AgGrid( df, gridOptions=grid_options, update_mode=GridUpdateMode.NO_UPDATE, allow_unsafe_jscode=True, # 允许自定义JS代码 height=500, fit_columns_on_grid_load=True ) # 隐藏文本框,用于JS传递选中行数据 hidden_input = st.text_input("", value="", key="hidden_selected", label_visibility="hidden") # 自定义JS:点击提交按钮时获取选中行并写入隐藏文本框 submit_js = """ <script> document.getElementById('submit_btn').addEventListener('click', function() { // 获取AgGrid实例 const gridDiv = document.querySelector('.ag-root-wrapper'); const gridApi = gridDiv?.__agGridInstance?.api; if (!gridApi) return; // 获取选中行数据,转换为JSON字符串 const selectedRows = gridApi.getSelectedRows(); const jsonData = JSON.stringify(selectedRows); // 写入隐藏的Streamlit文本框 const hiddenInput = document.querySelector('[data-testid="stTextInput"][aria-label=""]'); if (hiddenInput) { hiddenInput.value = jsonData; // 触发Streamlit组件更新 hiddenInput.dispatchEvent(new Event('input', {bubbles: true})); } }); </script> """ # 渲染提交按钮和JS代码 st.markdown(submit_js, unsafe_allow_html=True) st.button("提交选中行", key="submit_btn") # 处理选中行数据,发送GET请求 if st.session_state.hidden_selected: try: selected_rows = json.loads(st.session_state.hidden_selected) # 转换为DataFrame方便处理(可选) selected_df = pd.DataFrame(selected_rows).drop("row_id", axis=1) # 生成查询参数(这里根据需求调整参数格式) query_params = { "selected_rows": selected_df.to_json(orient="records") # 或者按列拆分参数,比如"col0": ",".join(selected_df["Col_0"].astype(str)) } # 发送GET请求(替换为目标URL) target_url = "https://your-target-url.com/api" response = requests.get(target_url, params=query_params) st.success(f"请求发送成功,响应状态码:{response.status_code}") st.subheader("选中行预览") st.dataframe(selected_df) # 清空隐藏输入,避免重复处理 st.session_state.hidden_selected = "" except Exception as e: st.error(f"处理失败:{str(e)}")
关键细节说明
GridUpdateMode.NO_UPDATE:彻底禁用AgGrid的自动更新触发,避免每次选中行都触发Streamlit重渲染,从根源解决卡顿问题。getRowId配置:设置行唯一标识,确保在排序、过滤、分页后,AgGrid仍能准确识别选中的行,不会出现选中行混乱的情况。- 自定义JS传递数据:利用Streamlit的隐藏文本框作为JS和Python的桥梁,点击按钮时主动获取选中行并传递,而非依赖AgGrid的内置回调。
- 会话状态处理:通过
st.session_state存储临时数据,避免页面重绘丢失选中状态,同时确保请求发送后清空缓存,防止重复提交。
纯客户端备选方案(无需后端请求)
如果只需要在客户端处理选中行(比如导出、本地展示),可以修改JS部分直接处理数据,无需传递回Python:
// 修改提交按钮的JS逻辑,直接在客户端处理 document.getElementById('submit_btn').addEventListener('click', function() { const gridDiv = document.querySelector('.ag-root-wrapper'); const gridApi = gridDiv?.__agGridInstance?.api; if (!gridApi) return; const selectedRows = gridApi.getSelectedRows(); // 客户端处理逻辑:比如导出为CSV const csvContent = "data:text/csv;charset=utf-8," + Object.keys(selectedRows[0]).join(",") + "\n" + selectedRows.map(e => Object.values(e).join(",")).join("\n"); const encodedUri = encodeURI(csvContent); const link = document.createElement("a"); link.setAttribute("href", encodedUri); link.setAttribute("download", "selected_rows.csv"); document.body.appendChild(link); link.click(); document.body.removeChild(link); });
内容的提问来源于stack exchange,提问作者mainstringargs
相关产品推荐
相关产品推荐

