Hello all,
I have a data_editor frame in my program that allows users to enter part numbers to assign them to a machine.
The first column is a dropdown with a list of parts. When a user selects a part in this column, I would like to populate the ‘part description’ and ‘category’ fields automatically.
Here is my current code:
- The first part uses session_state to preload a DataFrame with a query from a MySQL database. Right now it is empty, but will have parts in it once they are added.
- The second is the on_change callback, ‘callback_steps()’.
This callback is supposed to check the part number against another query that contains all of the parts, their description, and their category. - The last part is supposed to copy the dataframe from session_state and generate a new data_editor with the updated data, but all that gets filled in is the ‘part_number’ column (which contains the drawdown) and everything else is blank.
if "panel_part_df" not in st.session_state:
st.session_state["panel_part_df"] = pd.DataFrame(panel_part_query)
def callback_steps():
if "my_key2" in st.session_state:
if len(st.session_state["my_key2"]["added_rows"]) > 0:
df_copy = st.session_state["my_key2"].copy()
for change_dict in df_copy["added_rows"]:
# Populate the part_description, manufacturer_name, and category_name fields
part_desc = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'part_description'].item() # Gets the part_description for this part.
man_name = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'manufacturer_name'].item()
cat_name = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'category_name'].item()
st.session_state["panel_part_df"].loc[
st.session_state["panel_part_df"]['manufacturer_num'] == change_dict['manufacturer_num'], [
'part_description']] = part_desc
st.session_state["panel_part_df"].loc[
st.session_state["panel_part_df"]['manufacturer_num'] == change_dict[
'manufacturer_num'], 'manufacturer_name'] = man_name
st.session_state["panel_part_df"].loc[
st.session_state["panel_part_df"]['manufacturer_num'] == change_dict[
'manufacturer_num'], 'category_name'] = cat_name
st.write(st.session_state["panel_part_df"])
modified_df = st.session_state["panel_part_df"].copy()
st.data_editor(modified_df,
key="my_key2",
num_rows="dynamic",
column_order=(
"manufacturer_num", "quantity", "part_description", "manufacturer_name",
"category_name"),
column_config={
"manufacturer_num": st.column_config.SelectboxColumn(
"Manufacturer #",
width='large',
options=all_part_query['manufacturer_num'],
required=True
)
},
use_container_width=True,
on_change=callback_steps(),
disabled=("part_description", "manufacturer_name", "category_name"),
)
A similar post was made about this, but I cannot figure out how they got it to work. I have been working on this for the last 8 hours and I need a second set of eyes to help me out.
Thanks,
Andrew
Also, here is the complete program for reference:
import streamlit as st
import pandas as pd
from sqlalchemy import text, Table, Column, Integer, String, MetaData, ForeignKey, insert, update
metadata_obj = MetaData()
manufacturer_table = Table(
"manufacturers",
metadata_obj,
Column("manufacturer_id", Integer, primary_key=True),
Column("manufacturer_name", String(256), nullable=False),
)
category_table = Table(
"categories",
metadata_obj,
Column("category_id", Integer, primary_key=True),
Column("category_name", String(120))
)
parts_table = Table(
"parts",
metadata_obj,
Column("part_id", Integer, primary_key=True),
Column("manufacturer_num", String(256), nullable=False),
Column("manufacturer_id", Integer, ForeignKey("manufacturers.manufacturer_id"), nullable=False),
Column("part_description", String(265)),
Column("category_id", String(256), ForeignKey("categories.category_id"), nullable=False),
)
st.set_page_config(layout="wide")
if st.button("Clear session_state"):
keys = list(st.session_state.keys())
for key in keys:
st.session_state.pop(key)
st.markdown("Use this page to assign parts to a panel.")
# Initialize connection.
conn = st.connection('mysql', type='sql')
# Perform queries.
model_query = conn.query('SELECT model_num FROM panels;', ttl=0)
all_part_query = conn.query('SELECT parts.manufacturer_num, manufacturers.manufacturer_name, parts.part_description, categories.category_name\
FROM parts\
JOIN manufacturers ON parts.manufacturer_id=manufacturers.manufacturer_id\
JOIN categories ON parts.category_id=categories.category_id;', ttl=0)
category_query = conn.query('SELECT category_id, category_name FROM categories;', ttl=0)
manufacturer_query = conn.query('SELECT manufacturer_id, manufacturer_name FROM manufacturers;', ttl=0)
st.header("Select panel:", anchor=False, divider="orange")
panel_option = st.selectbox('Panel', model_query)
# part_option = st.selectbox('Part', all_part_query)
# quantity = st.text_input('Quantity')
panel_part_query = conn.query("SELECT parts.part_description, parts.manufacturer_num, manufacturers.manufacturer_name, categories.category_name, part_panel.quantity\
FROM parts\
JOIN manufacturers ON parts.manufacturer_id = manufacturers.manufacturer_id\
JOIN categories ON parts.category_id = categories.category_id\
JOIN part_panel ON parts.part_id = part_panel.part_id\
JOIN panels ON part_panel.panel_id = panels.panel_id\
WHERE panels.model_num = '{x}';".format(x=panel_option), ttl=0)
df = pd.DataFrame(
all_part_query) # , columns=("part_id", "Part #", "manufacturer", "manufacturer_num", "part_description"))
empty_df = pd.DataFrame(columns=['Manufacturer #', 'Quantity', 'Description'])
if "panel_part_df" not in st.session_state:
st.session_state["panel_part_df"] = pd.DataFrame(panel_part_query)
def callback_steps():
if "my_key2" in st.session_state:
if len(st.session_state["my_key2"]["added_rows"]) > 0:
df_copy = st.session_state["my_key2"].copy()
for change_dict in df_copy["added_rows"]:
# Populate the part_description, manufacturer_name, and category_name fields
part_desc = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'part_description'].item() # Gets the part_description for this part.
man_name = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'manufacturer_name'].item()
cat_name = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'category_name'].item()
st.session_state["panel_part_df"].loc[
st.session_state["panel_part_df"]['manufacturer_num'] == change_dict['manufacturer_num'], [
'part_description']] = part_desc
st.session_state["panel_part_df"].loc[
st.session_state["panel_part_df"]['manufacturer_num'] == change_dict[
'manufacturer_num'], 'manufacturer_name'] = man_name
st.session_state["panel_part_df"].loc[
st.session_state["panel_part_df"]['manufacturer_num'] == change_dict[
'manufacturer_num'], 'category_name'] = cat_name
st.write(st.session_state["panel_part_df"])
modified_df = st.session_state["panel_part_df"].copy()
st.data_editor(modified_df,
key="my_key2",
num_rows="dynamic",
column_order=(
"manufacturer_num", "quantity", "part_description", "manufacturer_name",
"category_name"),
column_config={
"manufacturer_num": st.column_config.SelectboxColumn(
"Manufacturer #",
width='large',
options=all_part_query['manufacturer_num'],
required=True
)
},
use_container_width=True,
on_change=callback_steps(),
disabled=("part_description", "manufacturer_name", "category_name"),
)
# st.write(st.session_state["my_key2"])
if st.button("Save changes"):
if len(st.session_state["my_key2"]["added_rows"]) > 0:
df_copy = st.session_state["my_key2"].copy()
indexList = [] # get old value
for change_dict in df_copy["added_rows"]:
if 'quantity' in change_dict:
st.write(change_dict['manufacturer_num'])
part_desc = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'part_description'].item() # Gets the part_description for this part.
cat_name = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'category_name'].item()
man_name = all_part_query[all_part_query['manufacturer_num'] == change_dict['manufacturer_num']][
'manufacturer_name'].item()
# find category_id from categories_table using category_name
cat_id = category_query[category_query['category_name'] == cat_name]['category_id'].item()
man_id = manufacturer_query[manufacturer_query['manufacturer_name'] == man_name][
'manufacturer_id'].item()
change_dict['part_description'] = part_desc
change_dict['manufacturer_id'] = man_id
change_dict['category_id'] = cat_id
st.write(change_dict)
with conn.session as session:
session.execute(insert(parts_table).values(change_dict))
session.commit()
else:
st.write("Please enter a quantity for all new rows")
# with conn.session as session:
# session.execute(insert(parts_table).values(change_dict))
# session.commit()
if len(st.session_state["my_key2"]["edited_rows"]) > 0:
df_copy = st.session_state["my_key2"].copy()
indexList = [] # get old value
for index, change_dict in df_copy["edited_rows"].items():
for changed_column, new_value in change_dict.items():
panel_id = df.iloc[index, 0]
indexList.append(index)
# st.write(indexList)
for i in indexList:
del st.session_state["my_key2"]["edited_rows"][i]
st.rerun()
if st.button('Assign'):
st.write("TODO")
# panel_id = conn.query('SELECT panel_id from panels WHERE model_num = "{x}";'.format(x = panel_option), ttl=0)
# panel_id = panel_id.at[0,'panel_id']
# part_id = conn.query('SELECT part_id from parts WHERE manufacturer_num = "{x}";'.format(x = part_option), ttl=0)
# part_id = part_id.at[0,'part_id']
# t = text("INSERT INTO part_panel (panel_id, part_id, quantity) VALUES (:panel_id2, :part_id2, :quantity2);")
# with conn.session as session:
# session.execute(t, {"panel_id2": panel_id, "part_id2": part_id, "quantity2": quantity})
# session.commit()
st.header("Parts assigned to {x}:".format(x=panel_option), anchor=False, divider="orange")
st.button("Refresh")
# st.dataframe(df2, hide_index=True, use_container_width=True, )
st.header("All Parts:", anchor=False, divider="orange")
st.dataframe(df, hide_index=True,
use_container_width=True, ) # column_order=("part_number", "manufacturer", "manufacturer_num", "part_description"))
# vendor_query = conn.query('SELECT vendor_name FROM vendors;', ttl=10)
# vendor
# vendor_option = st.selectbox('Vendor', vendor_query)
# vendor_num
# vendor_num = st.text_input('Vendor #', '')