Hi everyone,
I’m facing an issue with the Patch()
module in my Dash application deployed on AWS Elastic Beanstalk. The Patch()
module works well when I have a few elements in the children (around 5). However, when the number of items increases to around 10 or more, the partial property update doesn’t work as expected.
Here’s the problem I’m encountering:
- When I remove an item, the item is removed from the list, but it is not removed from the children.
- Similarly, when I try to re-add a removed item, it does not get re-added to the children.
- If I navigate to a different page and then return to the page with the
Patch()
implementation, the models are rendered correctly based on the list, but the removed items are not re-rendered, and re-adding them still doesn’t work.
Additionally, I noticed the following error in the console:
{message: 'Callback error updating ac-selection-content.children', html: '<html>\r\n<head><title>413 Request Entity Too Large<…disable MSIE and Chrome friendly error page -->\r\n'}
It seems like there might be a limitation related to the total data transferred between the application, but I’m not sure. I don’t see any other errors in the app logs.
Here’s a simplified version of my code:
import dash
import dash_bootstrap_components as dbc
from dash import html, dcc, Output, Input, State, Patch, ALL, callback_context
import random
from faker import Faker
fake = Faker()
app = dash.Dash(
__name__,
external_stylesheets=[
dbc.themes.BOOTSTRAP,
dbc.icons.BOOTSTRAP,
dbc.icons.FONT_AWESOME,
],
)
server = app.server
def generate_random_items(num_items=10):
models = ["Model 1", "Model 2", "Model 3", "Model 4", "Model 5", "Model 6", "Model 7", "Model 8", "Model 9", "Model 10"]
statuses = ["Testing", "Pending", "Completed", "In Progress"]
countries = ["USA", "Canada", "Germany", "France", "Brazil"]
items = []
for _ in range(num_items):
item = {
"Model": random.choice(models),
"Serial Number": str(random.randint(10000, 99999)),
"Status": fake.company_suffix(),
"Country": fake.country(),
"Comments": fake.text(max_nb_chars=350)
}
items.append(item)
return items
item_data = generate_random_items(30)
app.layout = html.Div(
[
dcc.Store(
id="data-selection", data={"suitable_items": item_data, "removed_items": []}
),
html.Div(
id="removed-aircraft-content",
children=[],
style={
"display": "grid",
"grid-template-columns": "repeat(3, 1fr)",
"gap": "16px",
},
),
html.Div(
id="selection-content",
children=[],
style={
"display": "grid",
"grid-template-columns": "repeat(3, 1fr)",
"gap": "16px",
},
),
],
style={"padding": "16px"},
)
@app.callback(
Output("data-selection", "data"),
Input({"type": "remove-model-ac-selection", "item": ALL}, "n_clicks"),
Input({"type": "readd-model-ac-selection", "item": ALL}, "n_clicks"),
State("data-selection", "data"),
)
def update_item_data(remove_clicks, readd_clicks, selection_data_flow):
trigger_id = callback_context.triggered_id
if trigger_id:
if "type" in trigger_id:
if trigger_id["type"] == "remove-model-ac-selection":
if "index" not in trigger_id:
aircraft_name = trigger_id["item"]
selection_data_flow["removed_items"].append(aircraft_name)
elif trigger_id["type"] == "readd-model-ac-selection":
if "index" not in trigger_id:
aircraft_name = trigger_id["item"]
selection_data_flow["removed_items"].remove(aircraft_name)
return selection_data_flow
@app.callback(
Output("removed-aircraft-content", "children"),
Input("data-selection", "data"),
)
def rendering_removed_component_images(selection_data_flow):
removed_items = selection_data_flow["removed_items"]
removed_items_set = set(removed_items)
list_of_divs_removed_items = []
for item in removed_items_set:
list_of_divs_removed_items.append(
html.Div(
html.Div([
html.Div(item, style={"marginRight":"8px"}),
html.Button(
"REadd",
id={"type": "readd-model-ac-selection", "item": item},
)
], style={"font-weight": "bold", "display":"flex", "marginBottom":"8px"}),)
)
return html.Div(list_of_divs_removed_items, style={
"display": "grid",
"grid-template-columns": "repeat(3, 1fr)",
"gap": "16px",
})
@app.callback(
Output("selection-content", "children"),
Input("data-selection", "data"),
State("selection-content", "children"),
)
def rendering_selection_component_images(selection_data_flow, current_children):
items_list = selection_data_flow["suitable_items"]
removed_items = selection_data_flow["removed_items"]
sorted_item_list = sorted(
items_list,
key=lambda x: (x["Model"], int(x["Serial Number"])),
)
current_items = set()
if current_children:
for child in current_children:
if "id" in child["props"] and "model" in child["props"]["id"]:
current_items.add(child["props"]["id"]["model"])
new_items = set()
for row in sorted_item_list:
item_full_name = f"{row['Model']} S/N {row['Serial Number']}"
if item_full_name in removed_items:
continue
new_items.add(item_full_name)
items_to_add = new_items - current_items
items_to_remove = current_items - new_items
patch = Patch()
for child in current_children:
if "id" in child["props"] and "model" in child["props"]["id"]:
if child["props"]["id"]["model"] in items_to_remove:
patch.remove(child)
for row in sorted_item_list:
item_full_name = f"{row['Model']} S/N {row['Serial Number']}"
if item_full_name in items_to_add:
model_name = row["Model"]
serial_number = row["Serial Number"]
item_status = row["Status"]
item_country = row["Country"]
image = html.Div(model_name, style={"textAlign": "center", "fontSize": "16px"},)
index = sorted_item_list.index(row)
patch.insert(
index,
html.Div(
[
html.Div(
image,
),
html.Div(
[
html.Div(
f"{item_status} {item_full_name} ({item_country})",
style={"textAlign": "center",},
),
dbc.Button(
className="bi bi-x py-0 px-1",
color="danger",
id={
"type": "remove-model-ac-selection",
"item": item_full_name,
},
style={"width": "26px", "height": "26px"},
),
],
style={"display": "flex", "justifyContent": "center", "alignItems": "center"},
),
],
id={"type": "model-card-div-selection", "model": item_full_name},
style={"border": "1px solid #E0E0E0", "borderRadius": "8px"},
),
)
return patch
if __name__ == "__main__":
app.run_server(debug=True, port=5000)
Only to let you know, The MRE is not 100% equal to my current application deployed on AWS, as my app has the items images and some other info, but the structure is the same
Has anyone encountered a similar issue or have any insights on potential limitations or solutions? Any help would be greatly appreciated!
Thank you!