Automatic insertion of user information with data_editor

Hi,

I’m new to Streamlit and I’m developing an interface where users can edit multiple configuration tables. The structures of the tables are different, but all contain a column with the username that inserted/updated the data.

With the data_editor I can easily fill the column for new rows, but I can’t find a way to modify the updated rows. Is there a simple way to implement this?

Let’s say I’m User4 and I edited colA in the first row with “E”. The “User” column should be automatically updated with “User4”.

I hope my explanation is clear. Thanks in advance!

import streamlit as st
import pandas as pd


loggedinUser = "User4"

df=pd.DataFrame(
    [{"colA":'A',"colB": 1,"User":'User1'},
     {"colA":'B',"colB": 2,"User":'User1'},
     {"colA":'C',"colB": 3,"User":'User2'},
     {"colA":'D',"colB": 4,"User":'User3'},]
)

with st.form('Table'):
    edit_df=st.data_editor(df,num_rows="dynamic",\
                          column_config={
                              "User": st.column_config.TextColumn(
                                            'User',
                                            help = 'Current Logged User',
                                            default = loggedinUser
                                        )
                          })
    submit_button = st.form_submit_button('Submit')
    if submit_button:
        try:
            st.success('SUCCESS')
        except Exception as e:
            st.error(e)

Hi, not as elegant as the new row, but you can ‘simulate’ this with a st.rerun each time you modify a row :

        loggedinUser = "User4"

        df = pd.DataFrame(
            [{"colA": 'A', "colB": 1, "User": 'User1'},
             {"colA": 'B', "colB": 2, "User": 'User1'},
             {"colA": 'C', "colB": 3, "User": 'User2'},
             {"colA": 'D', "colB": 4, "User": 'User3'}, ]
        )

        # Initialize session state to store the original dataframe
        if "original_df" not in st.session_state:
            st.session_state["original_df"] = df

        # Function to update user column for edited rows
        def update_user_column(edited_df):
            original_df = st.session_state["original_df"]
            for index, row in edited_df.iterrows():
                if not original_df.iloc[index].equals(row):
                    edited_df.at[index, "User"] = loggedinUser
            return edited_df

        # Display the data editor
        edit_df = st.data_editor(
            st.session_state["original_df"],
            num_rows="dynamic",
            column_config={
                "User": st.column_config.TextColumn(
                    'User',
                    help='Current Logged User',
                    default=loggedinUser,
                    disabled=True  # Make User column not editable directly by the user
                )
            },
            key="data_editor"
        )
        if not edit_df.equals(st.session_state["original_df"]):
            st.session_state["original_df"] = update_user_column(edit_df)
            st.rerun()

Hope, it’s what you are looking for !

@Faltawer you got the idea, but this solution fails to add new rows.

I also need the st.form. The DF is saved as a table when the submit button is pressed.

IndexError: single positional indexer is out-of-bounds
Traceback:
File "/usr/lib/python_udf/253c7765317f7edc435b297bf36bfec4180ecaae607b703adbcd0bce9b12d660/lib/python3.8/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 600, in _run_script
    exec(code, module.__dict__)
File "/tmp/appRoot/streamlit_app.py", line 41, in <module>
    st.session_state["original_df"] = update_user_column(edit_df)
File "/tmp/appRoot/streamlit_app.py", line 21, in update_user_column
    if not original_df.iloc[index].equals(row):
File "/usr/lib/python_udf/253c7765317f7edc435b297bf36bfec4180ecaae607b703adbcd0bce9b12d660/lib/python3.8/site-packages/pandas/core/indexing.py", line 1103, in __getitem__
    return self._getitem_axis(maybe_callable, axis=axis)
File "/usr/lib/python_udf/253c7765317f7edc435b297bf36bfec4180ecaae607b703adbcd0bce9b12d660/lib/python3.8/site-packages/pandas/core/indexing.py", line 1656, in _getitem_axis
    self._validate_integer(key, axis)
File "/usr/lib/python_udf/253c7765317f7edc435b297bf36bfec4180ecaae607b703adbcd0bce9b12d660/lib/python3.8/site-packages/pandas/core/indexing.py", line 1589, in _validate_integer
    raise IndexError("single positional indexer is out-of-bounds")

You can update the function :

        def update_user_column(edited_df):
            original_df = st.session_state["original_df"]
            for index, row in edited_df.iterrows():
                if index < len(original_df) and not original_df.iloc[index].equals(row):
                    edited_df.at[index, "User"] = loggedinUser
            return edited_df

Did handle the change of size with the new row :slight_smile:

Thanks @Faltawer ! Is there an alternative for st.rerun()? It stops the execution of the script and I can’t save the DF as a table.

Can you show me your code, i don’t have any problem to display, manipulate the df after the st.form().

I was able to adapt your solution into my code, Thanks @Faltawer !

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.