I’m using st.data_editor, which includes a checkbox column called “Save.” The expected flow is:
- The user edits one or more rows.
- Then they select the “Save” checkbox for the edited rows.
- Finally, they press the “Save Changes” button to process and save those records.
However, the behavior is inconsistent:
- Sometimes, when pressing the button, the message appears:
“No records selected for saving,” even when I had selected checkboxes. - Other times, the checkboxes are unchecked by themselves and the changes are not reflected.
- But sometimes it works correctly and saves the changes as expected.
I think it’s due to the loss of the checkbox state or the edits.
I would like
- The edits made to be retained.
- The selected checkbox to remain selected until the save is processed.
- The “Save Changes” button works reliably and consistently.
Is this possible?
This is the table and the save button.
with st.form("form_guardado"):
# tabla editable con columnas personalizadas, especifica como debe verse cada columna, ejm "Guardar": como checkbox, "Incidente": texto con límite de 7 caracteres,hide_index=True sirve para eliminar el index etc
df_edited = st.data_editor(df_styled, key="unique_data_editor", column_config={'id': None, 'Guardar': st.column_config.CheckboxColumn("Guardar", default=False), 'Incidente': st.column_config.TextColumn("Incidente", max_chars=7), 'Solucion_Ejecutada': st.column_config.TextColumn("Solución Ejecutada"),'Causa_Raiz': st.column_config.TextColumn("Causa_Raiz"),'Solucion2': st.column_config.TextColumn("Solucion2"),'Resumen_OT': st.column_config.TextColumn("Resumen_OT"),'Plantilla_OT': st.column_config.TextColumn("Plantilla_OT"), 'Avance' : st.column_config.TextColumn("Avance"),'HORA_INICIO': st.column_config.DatetimeColumn("HORA_INICIO", format="YYYY-MM-DD HH:mm:00"),'HORA_RECUPERACION': st.column_config.DatetimeColumn("HORA_RECUPERACION", format="YYYY-MM-DD HH:mm:00"),'Version': st.column_config.NumberColumn("Versión", disabled=True)}, disabled=["id","TMR","Tiempo_Efectivo", "Solo_CONTRATISTAS","Tiempo_Decimal","Tiempo_Efectivo_Decimal","Solucion_Ejecutada","Causa_Raiz","Solucion2","Resumen_OT", "Avance", "Estado_avance", "Usuario"], hide_index=True)
# Se ejecuta solo cuando el usuario presiona el botón
if st.form_submit_button("💾 Guardar cambios"):
# Muestra qué registros están marcados con el checkbox "Guardar"
try:
st.write("Valores de 'Guardar':", df_edited['Guardar'].unique())
f_save = df_edited[df_edited['Guardar']]
st.write("Registros a guardar:", f_save)
# Si ningún registro fue marcado, se detiene la ejecución con advertencia
if f_save.empty:
st.warning("No hay registros seleccionados para guardar")
st.stop()
# Conversión de fechas y tiempos
f_save['HORA_INICIO'] = pd.to_datetime(f_save['HORA_INICIO'], errors='coerce')
f_save['HORA_RECUPERACION'] = pd.to_datetime(f_save['HORA_RECUPERACION'], errors='coerce')
for col in ['Tiempo_Reloj', 'Tiempo_Telefonica']:
f_save[col] = pd.to_timedelta(f_save[col], errors='coerce')
f_save['TMR'] = f_save.apply(operacion_tmr, axis=1)
f_save['Solo_CONTRATISTAS'] = f_save.apply(operacion_contratista, axis=1)
f_save['Tiempo_Efectivo'] = f_save.apply(operacion_tefectivo, axis=1)
f_save['Tiempo_Decimal'] = f_save['Tiempo_Reloj'].apply(operacion_tdecimal)
f_save['Tiempo_Efectivo_Decimal'] = f_save.apply(operacion_ted, axis=1)
# Guardado
st.toast(f"Guardando {len(f_save)} registros...", icon="💾")
usuario = st.session_state.get("Usuario", "Desconocido")
progress_bar = st.progress(0)
status_text = st.empty()
# llama a la funcion guardar_registros, df_edited: la tabla completa, f_save: solo los registros a guardar, usuario: usuario activo en sesión
exito = guardar_registros(df_edited, f_save, usuario)
# si fue exitoso recarga los datos desde la base consulta_mysql()
if exito:
progress_bar.progress(100)
status_text.success("Datos actualizados")
st.session_state.df = consulta_mysql() # función que obtiene los datos desde la bd
st.session_state.df['Guardar'] = False
st.rerun()
else:
progress_bar.empty()
status_text.error("Error al guardar, verifique los datos")
# si ocurre un error muestra mensaje
except Exception as e:
st.error(f"Error crítico al guardar: {str(e)}")
st.exception(e)
This is the editable part of the table with the button.
Thank you!