I am trying to create a small app, that receives some data from an API, pushes it into a dataframe, which I want to modify and then send to another API. The issue is that I really want a button to trigger the download of the initial data. After receiving the data, I would like to modify it and then click another button to send it away.
What happens though, is after clicking the send button the app just runs from start without ever sending the data. If I remove the first button to receive the data, everything works as expected.
I think I do not fully understand how the session state works here. Maybe someone can explain.
Here is my code to reproduce (1.35.0):
import streamlit as st
import pandas as pd
def send_df_to_db(df):
print(f"Sending df to DB:\n{df}")
st.write("Sending df to DB:")
st.write(df)
def get_df(dummy):
df = pd.DataFrame(
[
{"command": "st.selectbox", "rating": 4, "is_widget": True},
{"command": "st.balloons", "rating": 5, "is_widget": False},
{"command": "st.time_input", "rating": 3, "is_widget": True},
]
)
return df
if st.button("Fetch Data"):
st.write("Fetching data...")
df = get_df(1)
with st.form("Edit form:"):
edited_df = st.data_editor(df, num_rows="dynamic")
submitted = st.form_submit_button("Submit modified data")
if submitted:
send_df_to_db(edited_df)
Take a look at: GitHub - seedoogithub/streamlitextend: streamlit_Extend , this the same problem we encountered . Its part of the streamlit design philosophy - the page always reloads on every event (which is great, and simplifies a lot of things and allows to build apps easily and quickly and with less bugs) . Yet if you want something a bit more advanced you always have to go for full react app . We implemented our project to solve this middle gap for our own app. It allows you to do the middle ground. Have events, without page reloading, but without doing a fully custom react app.
Thank you, this kind of confirms what I thought. There is no real solution, Streamlit just is this way.
Your project looks promising. I was working on something where I wanted mqtt data to update a df in a callback function. Your project could have lead me to the correct direction.
With session.state and you may be able to see @st.experimental_fragment
import streamlit as st
import pandas as pd
def send_df_to_db(df):
print(f"Sending df to DB:\n{df}")
st.write("Sending df to DB:")
st.write(df)
def get_df():
df = pd.DataFrame(
[
{"command": "st.selectbox", "rating": 4, "is_widget": True},
{"command": "st.balloons", "rating": 5, "is_widget": False},
{"command": "st.time_input", "rating": 3, "is_widget": True},
]
)
return df
# Initialize session state for the DataFrame
if 'df' not in st.session_state:
st.session_state.df = None
if st.button("Fetch Data"):
st.write("Fetching data...")
st.session_state.df = get_df()
if st.session_state.df is not None:
with st.form("Edit form:"):
edited_df = st.data_editor(st.session_state.df, num_rows="dynamic")
submitted = st.form_submit_button("Submit modified data")
if submitted:
send_df_to_db(edited_df)
# Clear the session state after sending
st.session_state.df = None
else:
st.write("No data fetched yet.")
Generally speaking, you will want to avoid nesting buttons inside buttons. Buttons don’t retain state; they’ll only be True immediately after they are clicked and then go back to False when the user makes their next click.
When you have something you don’t want to redo, you can use caching or Session State to save the info. Rule of thumb: if the loaded data is the same for all users, use caching. If the loaded data is specific to the user, use Session State. Additionally, if you have a process (or subprocess) you want to rerun independently of the rest of the app, use fragments.
@Oscar’s solution above shows a common way to use Session State with data download triggered by a button press.
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.