pages
Streamlit has an automatic method of adding pages to the sidebar menu. From the top menu, we create a directory named, pages.
The pages will be listed sorted by a leading number. In our example we will name the files, 1_add_row.py, 2_edit_row.py, 3_delete_row.py. Streamlit will remove the number from the file name and convert underscores to spacees.
Pages – add_row.py
The add_row.py file will allow the user to add a row to the database. We will use the tables column names and data types when creating the streamlit data editor widget.
Pages – add_row.py – main()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# pages / 1_add_row.py # -- LIBRARY ----------------------------------------------------------------- import streamlit as st # -- LOCAL ------------------------------------------------------------------- from streamlit_handler import StreamlitAddData def main(): st.set_page_config(layout="wide") # INIT if 'data_editor_add' not in st.session_state: st_handler = StreamlitAddData() st.session_state['st_handler'] = st_handler else: st_handler = st.session_state['st_handler'] # layout st.header("Add a New Row") # select box UI for which table selected_table = st_handler.selectbox_table() if selected_table is not None: # set the name of the table will be adding rows too st_handler.source_table_name = selected_table # display the data_editor on screen new_data = st_handler.fetch_empty_table() if st.button(label="Add Row", key="btn_add_row"): st_handler.add_source_data(new_data=new_data) if st_handler.query_success(): st.success("New rows added to the database") if __name__ == "__main__": main() |
Details about the code.
Here we are doing a similar thing as the home page. However I have created a class called streamlit_handler with a subclass of StreamlitAddData that will help with passing of the data from the database to the streamlit widgets.
We will review the streamlit_handler later in the tutorial.
pages – add_row.py – main() – session_state
One of the main issues with how the streamlit package works is that by default it is stateless, unless you use the streamlit session_state method.
1 2 3 4 5 6 7 8 |
def main(): st.set_page_config(layout="wide") # INIT if 'data_editor_add' not in st.session_state: st_handler = StreamlitAddData() st.session_state['st_handler'] = st_handler else: st_handler = st.session_state['st_handler'] |
Here we are checking if the session state has been set. If the session is set, we will re-invoking the session state. The st_handler object contains all of the data we need to add a row to the table.
pages – add_row.py – main() – select table
1 2 3 4 5 |
# layout st.header("Add a New Row") # select box UI for which table selected_table = st_handler.selectbox_table() |
We will add a select box so the user can choose which table they would like to add a row too.
pages – add_row.py – main() – data_editor
1 2 3 4 5 |
if selected_table is not None: # set the name of the table will be adding rows too st_handler.source_table_name = selected_table # display the data_editor on screen new_data = st_handler.fetch_empty_table() |
Here, we will wait until the user has selected a table from the select box. On the change event, the main() function will first fetch the table name from the select box. Second, using the st_handler method fetch_empty_table() will read the meta data about the selected table and populate the data_editor widget.
pages – add_row.py – main() – add_row button
1 2 3 |
if st.button(label="Add Row", key="btn_add_row"): st_handler.add_source_data(new_data=new_data) |
Now we will wait until the user presses the button labeled “Add Row” and will then invoke the add_source_data method, to write the data to the table.
pages – edit_row.py – main() – success div
1 2 |
if st_handler.query_success(): st.success("New rows added to the database") |
If the add_source_data method is successful, the query_success property will return True; and will display a message to the user.
pages – edit_row.py
The edit_row.py page follows a similar pattern as the add_row.py page with a few additions. We will add page navigation buttons and controls for pagination of the table data, let’s dig in.
pages – edit_row.py – main()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# pages / 2_edit_row.py # -- LIBRARY ----------------------------------------------------------------- import streamlit as st # -- LOCAL ------------------------------------------------------------------- from streamlit_handler import StreamlitEditData def main(): st.set_page_config(layout="wide", page_icon=":anchor:" ) if 'data_editor_update' not in st.session_state: st_handler = StreamlitEditData() st.session_state['st_handler'] = st_handler else: st_handler = st.session_state['st_handler'] st.title("Edit Rows") # select box UI for which table selected_table = st_handler.selectbox_table() if selected_table is not None: # set the name of the table will be adding rows too st_handler.source_table_name = selected_table st_handler.total_pages = st_handler.fetch_row_count() with st.sidebar: # Dropdown to select rows per page st_handler.selectbox_rows_per_page() # input box to select page number st_handler.input_page_select() # page nav controls st_handler.page_nav_controls() with st.container(border=True): edited_data = st_handler.data_editor_formatted() st.button(label="Update Rows", key="btn_update_rows", on_click=st_handler.update_source_data, args=(edited_data,) ) if st_handler.query_success(): st.success("Updateds saved to the database.") if __name__ == "__main__": main() |
Details about the code, similar to the add_row.py, we will use check if the session state has been set. If the session is set, we will re-invoking the session state. The st_handler object contains all of the data we need to edit a row in the table.
Next there are four parts to the page, checking session_state, the table selectbox, the sidebar, and the data_editor widget.
pages – edit_row.py – main() – session_state
1 2 3 4 5 6 7 8 9 10 |
def main(): st.set_page_config(layout="wide", page_icon=":anchor:" ) if 'data_editor_update' not in st.session_state: st_handler = StreamlitEditData() st.session_state['st_handler'] = st_handler else: st_handler = st.session_state['st_handler'] |
If the session is set, we will re-invoking the session state. The st_handler object contains all of the data we need to edit a row in the table.
pages – edit_row.py – main() – sidebar
1 2 3 4 5 6 |
with st.sidebar: # Dropdown to select rows per page st_handler.selectbox_rows_per_page() # input box to select page number st_handler.input_page_select() |
Streamlit automatically adds a link for every .py file in the pages directory. In addition, we will add two widgets below the page links in the sidebar.
pages – edit_row.py – main() – nav controls
1 2 |
# page nav controls st_handler.page_nav_controls() |
After the side bar, we will call the st_handler.page_nav_controls() method to print a row with multiple columns showing the page controls.
pages – edit_row.py – main() – data_editor
1 2 |
with st.container(border=True): edited_data = st_handler.data_editor_formatted() |
Below the page nav controls we will display the data_editor widget called by the st_handler.data_editor_formatted() method.
pages – edit_row.py – main() – update rows button
1 2 3 4 5 |
st.button(label="Update Rows", key="btn_update_rows", on_click=st_handler.update_source_data, args=(edited_data,) ) |
Next, we will display a button for when the user has completed their edits. The on_click argument specifies the function to call after the user clicks the button. Some Streamlit widgets support on_click and others on_change. In our case we will call the st_handler.update_source_data method.
Pages – edit_row.py – main() – success div
1 2 |
if st_handler.query_success(): st.success("Updateds saved to the database.") |
If the update_source_data method is successful, the query_success property will return True; and will display a message to the user.
Pages – delete_row.py
The delete_row.py page follows a similar pattern as the edit_row.py page with a few additions. We will add a column named Select to the dataset, allowing user to check which rows to delete. After pressing the Delete Rows button we will show a confirmation button to the user, let’s get started.
pages – delete_row.py – main()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# pages / 3_delete_row.py # -- LIBRARY ----------------------------------------------------------------- import streamlit as st # -- LOCAL ------------------------------------------------------------------- from streamlit_handler import StreamlitDeleteData def main(): st.set_page_config(layout="wide") # INIT if 'data_editor_delete' not in st.session_state: st_handler = StreamlitDeleteData() st.session_state['st_handler'] = st_handler else: st_handler = st.session_state['st_handler'] # layout st.header("Delete Rows") # select box UI for which table selected_table = st_handler.selectbox_table() if selected_table is not None: # Tell user what to do st.text("Check box in Select column to mark row for deletion") st_handler.source_table_name = selected_table st_handler.total_pages = st_handler.fetch_row_count() with st.sidebar: # Dropdown to select rows per page st_handler.selectbox_rows_per_page() # input box to select page number st_handler.input_page_select() # page nav controls st_handler.page_nav_controls() # source table data table_data = st_handler.data_editor_formatted() # delete the data from the table st.button(label="Delete Rows", key="btn_delete_rows", on_click=st_handler.prompt_for_confirmation, args=(table_data.query("Select == True").shape[0],) ) #if st.session_state['deletion_requested']: if st_handler.deletion_requested: # delete the data from the table st.button(label="Confirm Deletion", key="btn_confirm_delete", on_click=st_handler.delete_source_data, args=(table_data.query("Select == True"),)) if st_handler.query_success(): # let user know rows have been deleted st.success("Selected rows deleted successfully.") table_data['Select'] = False st.session_state['st_handler'] = st_handler if __name__ == "__main__": main() |
Details about the code, similar to the edit_row.py, we will use check if the session state has been set. If the session is set, we will re-invoking the session state. The st_handler object contains all of the data we need to select which rows in the table to delete.
Next there are five parts to the page, checking session_state, the table selectbox, the sidebar, the data_editor widget, and confirmation from the user.
pages – delete_row.py – main() – session state
1 2 3 4 5 6 7 8 |
def main(): st.set_page_config(layout="wide") # INIT if 'data_editor_delete' not in st.session_state: st_handler = StreamlitDeleteData() st.session_state['st_handler'] = st_handler else: st_handler = st.session_state['st_handler'] |
If the session is set, we will re-invoking the session state. The st_handler object contains all of the data we need to delete a row in the table.
pages – delete_row.py – main() – table select box
1 2 3 4 5 |
# layout st.header("Delete Rows") # select box UI for which table selected_table = st_handler.selectbox_table() |
Add a header for the page, and then call the st_handler selectbox_table method, same as in addrow and edit_row pages.
pages – delete_row.py – main() – sidebar
1 2 3 4 5 6 |
with st.sidebar: # Dropdown to select rows per page st_handler.selectbox_rows_per_page() # input box to select page number st_handler.input_page_select() |
Streamlit automatically adds a link for every .py file in the pages directory. In addition, we will add two widgets below the page links in the sidebar.
pages – delete_row.py – main() – nav controls
1 2 |
# page nav controls st_handler.page_nav_controls() |
After the side bar, we will call the st_handler.page_nav_controls() method to print a row with multiple columns showing the page controls.
pages – delete_row.py – main() – data_editor
1 2 |
# source table data table_data = st_handler.data_editor_formatted() |
Below the page nav controls we will display the data_editor widget called by the st_handler.data_editor_formatted() method. The method is called from the subclass. The method will add a column named Select which is Boolean data type, and shown as a checkbox in thee data_editor widget.
pages – delete_row.py – main() – delete rows button
1 2 3 4 5 6 |
# delete the data from the table st.button(label="Delete Rows", key="btn_delete_rows", on_click=st_handler.prompt_for_confirmation, args=(table_data.query("Select == True").shape[0],) ) |
Next, we will display a button for when the user has completed which rows they want to delete. The on_click argument specifies the function to call after the user clicks the button. Some Streamlit widgets support on_click and others on_change. In our case we will call the st_handler.prompt_for_confirmation method.
pages – delete_row.py – main() – confirmation
1 2 3 4 5 6 |
if st_handler.deletion_requested: # delete the data from the table st.button(label="Confirm Deletion", key="btn_confirm_delete", on_click=st_handler.delete_source_data, args=(table_data.query("Select == True"),)) |
When the user selects they want to delete row(s) from the table, a confirmation button will be displayed. After clicking the confirmation button the st_handler.delete_source_data method will be called.
pages – delete_row.py – main() – success div
1 2 3 4 |
if st_handler.query_success(): # let user know rows have been deleted st.success("Selected rows deleted successfully.") table_data['Select'] = False |
If the delete_source_data method is successful, the query_success property will return True; and will display a message to the user.
Now, that we have reviewed the pages, on the next page we will dive into the StreamlitHandler Class and how it communicates with the Streamlit widgets and the database.
Leave a Reply