Comme nous pouvons le voir dans La partie relative à l'interactivité de la section Mise en route , une fonction de rappel peut accepter plusieurs entrées, mais a toujours une seule sortie.
Supposons que nous ayons deux blocs séparément qui doivent être mis à jour après le changement d’entrée. Bien sûr, le moyen le plus simple consiste à effectuer deux rappels avec la même entrée pour chacun des blocs. Le problème est que la requête est exécutée deux fois alors qu'une seule suffit pour obtenir toutes les données.
@app.callback(
dash.dependencies.Output('element_1', 'children'),
[dash.dependencies.Input('filter', 'value')])
def callback_element_1(filter):
return get_data(filter).el1
@app.callback(
dash.dependencies.Output('element_2', 'children'),
[dash.dependencies.Input('filter', 'value')])
def callback_element_2(filter):
return get_data(filter).el2
La solution que j’ai trouvée est d’envelopper ces éléments dans un seul bloc et de les restituer complètement avec une seule demande. Mais dans ce cas, tout le contenu statique du wrapper sera également actualisé, en particulier si les éléments initiaux sont éloignés les uns des autres dans DOM.
@app.callback(
dash.dependencies.Output('wrapper', 'children'),
[dash.dependencies.Input('filter', 'value')])
def callback_element_wrapper(filter):
data = get_data(filter)
return html.Div(
children=[
data.el1,
# more static content
data.el2,
]
)
Alors peut-être y at-il une manière plus élégante de produire en deux ou plusieurs éléments avec une seule demande?
Basé sur ceci , Il y a un moyen.
Ce que vous pouvez faire est de mettre à jour un "élément de signal" masqué (par exemple, une entrée de texte), qui met à jour les deux éléments principaux.
Exécutez la get_data(filter)
une fois et stockez le résultat dans une variable globale. Ensuite, au lieu de mettre à jour element_1
et element_2
, Met à jour cet élément de signal.
result = []
@app.callback(
dash.dependencies.Output('signal', 'value'),
[dash.dependencies.Input('filter', 'value')])
def callback_signal(filter):
global result
result = get_data(filter)
return filter
@app.callback(
dash.dependencies.Output('element_1', 'children'),
[dash.dependencies.Input('signal', 'value')])
def callback_element_1(filter):
return result.el1
@app.callback(
dash.dependencies.Output('element_2', 'children'),
[dash.dependencies.Input('signal', 'value')])
def callback_element_2(filter):
return result.el2
Dans mon cas, j’utilisais Dash dans un environnement à utilisateur unique et l’utilisation de la variable globale n’était pas un problème. Si vous avez plusieurs utilisateurs qui exécuteront l'application en même temps, les alternatives sont disponibles et vous pouvez les trouver dans le même lien.
Et si vous pouviez composer les écouteurs d'action dans une fonction externe? en utilisant l'exemple d'Oleh
def setup_action_callbacks(app):
result = []
@app.callback(
dash.dependencies.Output('signal', 'value'),
[dash.dependencies.Input('filter', 'value')])
def callback_signal(filter):
result = get_data(filter)
return filter
@app.callback(
dash.dependencies.Output('element_1', 'children'),
[dash.dependencies.Input('signal', 'value')])
def callback_element_1(filter):
return result.el1
@app.callback(
dash.dependencies.Output('element_2', 'children'),
[dash.dependencies.Input('signal', 'value')])
def callback_element_2(filter):
return result.el2
Tel que:
def get_app_layout(app):
setup_action_callbacks(app)
return html.Div()
app = DjangoDash(name="a_Nice_name", app_name="a_Nice_app_name")
app.layout = get_app_layout(app)