For my app, I want the text input to have default value based on a df value reading from the database. The user has right to put whatever they want into the text_input. However, when the user click the button, it will save the new user input to the dataframe and trigger the whole process to rerun so we will reread default_value from database, and set it as a default value to the text input.
Notice the default_value is changing since we are updating the database.
I checked the on_click method but it seems only setting the text_input value to something fixed or cannot get my database change because I do the db change after have the button clicked.
default_value = get_a_df_from_db().iloc[0][0]
re = st.text_input('reuu', key='teuust', value=default_value)
rr = st.button('test', key='vv')
if rr:
store re to database
Please suggest how should I do under this circumstance.
import streamlit as st
import pandas as pd
#########################
# A fake data source;
# Pretend this isn't here
#########################
if 'my_db' not in st.session_state:
st.session_state.my_db = pd.DataFrame({'A':['a','b'],'B':['c','d']})
#########################
# Read/Write Commands for your data source
def get_from_db():
'''A function that queries your database
'''
return st.session_state.my_db
def write_to_db(row, column, value):
'''A function that writes to your database
'''
st.session_state.my_db.loc[row,column] = value
# Update script to run when user commits a change
def commit_change(row, column, value):
'''A function to update your database and refresh your data from source
'''
write_to_db(row, column, value)
st.session_state.df = get_from_db()
# Use session state to only read from source on first load
if 'df' not in st.session_state:
st.session_state.df = get_from_db()
st.subheader('Current Database')
st.write(st.session_state.df)
column = st.selectbox('Column',st.session_state.df.columns)
row = st.selectbox('Row',st.session_state.df.index)
current_value = st.session_state.df.loc[row,column]
st.session_state.default = current_value
new = st.text_input(f'Cell {column}{row}',value=st.session_state.default)
st.button('Commit', on_click=commit_change, args=[row,column,new])
Thanks so much for your reply. Under your example, my question would be like:
new = st.text_input(f'Cell {column}{row}', value='please put input inside')
So I always want the text input to display âplease put input insideâ after the user click commit and the page refreshes. The user can type in whatever they want afterwards, but I just want to have that default value always being dispalyed as something unchanged. And after hitting the commit button, the df will be refreshed as what you have in your current example.
The workflow should be like:
text input display âplease put input insideâ
user type something for that
user click commit, df gets refreshed, the text input gets back to display âplease put input insideâ
iterative we go back to step 2
In the current code, after hitting the commit button, the text input keep having the last input value instead of my default setting.
Then instead of using a default value, you use a key with the widget and overwrite the stored value. You can use the placeholder keyword argument if you want âinstruction textâ written within the empty widget.
import streamlit as st
import pandas as pd
#########################
# A fake data source;
# Pretend this isn't here
#########################
if 'my_db' not in st.session_state:
st.session_state.my_db = pd.DataFrame({'A':['a','b'],'B':['c','d']})
#########################
# Read/Write Commands for your data source
def get_from_db():
'''A function that queries your database
'''
return st.session_state.my_db
def write_to_db(row, column, value):
'''A function that writes to your database
'''
st.session_state.my_db.loc[row,column] = value
# Update script to run when user commits a change
def commit_change(row, column, value):
'''A function to update your database and refresh your data from source
'''
write_to_db(row, column, value)
st.session_state.df = get_from_db()
st.session_state.input = ''
# Use session state to only read from source on first load
if 'df' not in st.session_state:
st.session_state.df = get_from_db()
st.subheader('Current Database')
st.write(st.session_state.df)
column = st.selectbox('Column',st.session_state.df.columns)
row = st.selectbox('Row',st.session_state.df.index)
current_value = st.session_state.df.loc[row,column]
new = st.text_input(f'Enter New Cell Value for {column}{row}',key='input', placeholder='Enter value here')
st.button('Commit', on_click=commit_change, args=[row,column,new])
Thanks so much for your solution! Iâm still confused about one part. I am trying to understand those strange behaviour when session state gets update for buttons/text inputs.
Workflow:
User type something in âEnter New Cell Valueâ and hit commit (as for my understanding, since the session state variable is changed, so the program does a rerun, and hence the âshould stay the same as default text inputâ get the new default_value (since commit changes db) cell value.
User type something in âShould stay the same as defaultâ and click the button test. However under this situation, whatever user just typed in âShould stay the sameâ is still there instead of the default value. Why is this? Shouldnât it be the same as since the the user types in something/clicks the button, so session state variable changed, so the program does a rerun, hence it displayes the default value?
The other code stays the same except for this:
if 'my_db' not in st.session_state:
st.session_state.my_db = pd.DataFrame({'A':['a','b'],'B':['c','d']})
def get_from_db():
return st.session_state.my_db
def write_to_db(value):
st.session_state.my_db.insert(0, value, [value, value])
def commit_change(value):
write_to_db(value)
st.session_state.df = get_from_db()
if 'df' not in st.session_state:
st.session_state.df = get_from_db()
st.subheader('Current Database')
st.write(st.session_state.df)
rr = st.button('test', key='vv')
default_value = st.session_state.my_db.iloc[0][0]
for i in range(1):
test1 = st.text_input('Should stay the same as default value after clicking button test', key='test1' + str(i), value=default_value)
new = st.text_input(f'Enter New Cell Value',key='input', placeholder='Enter value here')
m = st.button('Commit', on_click=commit_change, args=[new])
You need to use a key for the widget and not the value keyword parameter. If there is no change to the construction of the widget it will retain any edits a user has given it.
By using a key in session state and manually assigning a value to that key, you can control the state of the widget. The default value only impacts the creation of the widget; if there is no change to the creation of the widget, then any reruns of the pages will have the widget remembering what the user last entered. It doesnât matter how many times you query a new âdefault value.â If you keep pulling the same default value, then Streamlit doesnât know that itâs not the same widget.
If you want to ârefreshâ a widget you either have to manually assign its state through its key or destroy it (and create a new one).
You can destroy a widget by using a different key or changing any of its defining parameters. Otherwise, you can destroy it by not rendering it on the page (and re-rendering it on a later rerun).
Iâm having trouble understanding. Please can you rephrase what your remaining question is?
If you want to clear the widget when you enter a new value to commit, you need to put the line back into the commit function that assigns an empty string to that widget.
If I change the construction of one button of the page, will the whole pageâs items all being refreshed?
(i.e. I change only one widget, the whole page knows I have some change, hence the whole pages widgets get a refresh?)
So in workflow step 1: since the commit buttonâs on_click method captures a new change (changing any of its defining parameters), so streamlit recognizes it as a new widget change, so the whole pagesâ buttons/text inputs get refreshed, hence the value=default_value worked
In workflow step2: although the default_value itself changed, it is not treated as a change for value=default_value (this is not changing defining parameters), so not treated as a widget change, so nothing changed on page.
If you change the construction of a single widget, only that widget will be reconstructed from scratch. All other widgets that havenât had their parameters changed will keep their memory of what the user had last entered.
The arguments for the on_click and on_change are as little different. Widgets wonât be reconstructed from different values passed to args. The values within args are things that are expected to change.
In workflow 1, the test input widget is constructed with a different default value, so that widget in and of itself is reconstructed from scratch because it has a new build parameter. The buttons and other input saw no change in construction and were not affected. If anything had been changed in the second input, it would continue to remember that value.
In workflow 2, the default value did not change so the test input widget retains its memory (i.e. its state) and is not reconstructed. What you see in the widget is the user input and not the âdefault valueâ if the user has entered anything into it since construction. Furthermore, the text input for committing changes has no change to its build parameters and is not reconstructed; it remembers whatever the user last had there, too.
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.