Фон
Da sh веб-приложения имеют экземпляр приложения da sh, обычно называемый app
, и инициируется следующим образом:
app = dash.Dash(__name__)
Затем добавляются обратные вызовы в приложение с помощью callback
декоратора:
@app.callback(...)
def my_function(...):
# do stuff.
В большинстве найденных вами руководств обратные вызовы определяются со всем макетом приложения в app.py
. Конечно, это просто способ работы MWE. В реальном приложении разделение кода на модули и пакеты значительно улучшило бы читаемость и удобство обслуживания, но наивное разделение обратных вызовов и макетов приводит к циклическому импорту.
Вопрос
Каким будет правильный способ отделения обратных вызовов и макетов от app.py
в одностраничном приложении?
MWE
Вот минимальный (не) рабочий пример с проблемой
Файловая структура
.
├── my_dash_app
│ ├── app.py
│ └── views
│ ├── first_view.py
│ └── __init__.py
└── setup.py
setup.py
import setuptools
setuptools.setup(
name='dash-minimal-realworld',
version='1.0.0',
install_requires=['dash>=1.12.0'],
packages=setuptools.find_packages(),
)
app.py
import dash
from my_dash_app.views.first_view import make_layout
app = dash.Dash(__name__)
app.layout = make_layout()
if __name__ == '__main__':
app.run_server(debug=True)
first_view.py
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from my_dash_app.app import app
def make_layout():
return html.Div([
dcc.Input(id='my-id', value='initial value', type='text'),
html.Div(id='my-div')
])
@app.callback(Output(component_id='my-div', component_property='children'),
[Input(component_id='my-id', component_property='value')])
def update_output_div(input_value):
return 'You\'ve entered "{}"'.format(input_value)
Запуск python ./my_dash_app/app.py
приводит к циклической зависимости:
ImportError: cannot import name 'make_layout' from 'my_dash_app.views.first_view' (c:\tmp\dash_minimal_realworld\my_dash_app\views\first_view.py)