I am using st.data_editor and is it ALMOST working correctly.
I have a pseudo-ORM list of objects connected to streamlit. I want to set it up that whenever a cell is edited, the value is immediately updated in the database.
I use the
edited_rows state variable to know what was changed, and pass it back to the ORM objects using
setattr(obj, changed_key, new_value).
However, I notice that after I make a second edit, both edits appear in the
edited_rows dictionary. This causes my setup to handle the same change multiple times.
I tried clearing it using
st.session_state[key]["edited_rows"].clear() but that did not have any effect.
Is this intentional behavior? Is there a solution for this use case?
- Streamlit version: 1.23.1
- Python version: 3.11
- Using Conda?
- OS version: Ubuntu
- Browser version: Firefox
The behavior you’re experiencing with the edited_rows dictionary in Streamlit’s st.data_editor is intentional. The edited_rows dictionary accumulates all the edits made in the data editor until the app is rerun or the session state is reset. This behavior allows you to access and handle all the changes made by the user during the session.
To address your use case of handling each change only once, you can modify your code to keep track of the changes you have already processed. Here’s a possible approach:
- Create a set to store the keys of the already processed changes:
if "processed_changes" not in st.session_state:
st.session_state.processed_changes = set()
- Iterate over the edited_rows dictionary, but only process the changes that haven’t been processed before:
for row_key, changed_values in st.session_state.edited_rows.items():
if row_key not in st.session_state.processed_changes:
# Process the changes for this row
obj = your_orm_objects[row_key]
for column_key, new_value in changed_values.items():
setattr(obj, column_key, new_value)
# Add the row key to the set of processed changes
By using the set
processed_changes to keep track of the changes that have already been processed, you ensure that each change is handled only once, even if multiple edits occur.
Remember to adapt the code above to fit your specific use case, including the names of your ORM objects and the appropriate logic for processing the changes.
I hope this helps resolve the issue and allows you to handle each change correctly in your Streamlit app.
Thanks! I indeed went on with a similar approach:
def _handle_table_changed(self, key_name: str):
new_state = st.session_state[key_name]
if "edited_rows" in new_state:
for index, change_dict in new_state["edited_rows"].items():
source_object = self.data[index]
for changed_field, new_value in change_dict.items():
# the getattr() check is required because streamlit does not remove entries from the modification
if getattr(source_object, changed_field) != new_value:
setattr(source_object, changed_field, new_value)
# new_state["edited_rows"].clear() Disabled because no effect
def render(self, key_name: str):
Because a row can be modified multiple times, I have to check on a per-value basis (this is the getattr line). It can theoretically cause performance issues in large sessions, but I’ll cross that bridge when we get there…
This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.