background
Plotly Dash is a Python web application framework that helps us quickly build beautiful, responsive, interactive, data visualization pages. Unfortunately, an app that can only display data is not always very useful. If we need a complete web application, we have to figure out a way to use its backend Flask .
question
Although Dash borrows the Flask shell, this Flask runs in a sandbox and has a lot less functionality than normal Flask. For example, the following functions do not need to be upgraded to the Dash enterprise version.
- Database integration
- Certification
- Multi-page, multi-route support
- custom style
etc
design
To overcome all of the above problems, instead of using Dash's own Flask, we can create a basic Flask app and put our Dash app on top of it.
in principle
- -- Ability to create any type of application with Dash and Flask.
- Full-featured -- Both Dash and Flask must be full-featured, with no functional limitations.
- Customizable -- Ability to customize the styles applied.
- Concise -- Create a Dash application quickly and easily.
solution
In general, we can achieve our goal in two ways.
- __Sub-application__: Create a basic Flask application, use this Flask as the parent server to initialize the Dash application, and register the Dash application as a sub-application with a custom route.
- __iframe__: Create a basic Flask application, put the Dash application in a
iframe
, and use Flask to load theseiframe
.
which is better
Compared with placing the Dash application in iframe
, although this method looks the simplest, it will introduce other problems because of the completely isolated characteristics of iframe
:
- __Difficult to customize__:
iframe
cannot change the application iniframe
through css/js. iframe
: Because 0622b64043692c has a different routing system from the main frame, clicking a link insideiframe
will not trigger the main frame to jump.- __Cannot extend__:
iframe
scheme does not support multi-page Dash applications.
For the above reasons, we believe that using sub-applications is a more flexible and general solution.
code structure
The code structure of the basic Flask is as follows:
├── app
│ ├── dash_apps -- 所有的Dash应用都在这个目录
│ │ ├── custom_dash_app.py
│ │ ├── experiment_detail_dash_app.py
│ │ ├── experiment_list_dash_app.py
│ │ └── __init__.py
│ ├── __init__.py
│ ├── static
│ │ └── styles.css -- Custom CSS styles
│ ├── templates
│ │ ├── dash_layout.html -- Dash应用的layout
│ │ ├── header.html -- Header
│ │ ├── index.html -- 主页面
│ │ └── layout.html -- 主页面的layout
│ └── views.py -- Flask路由和主页面导航菜单定义
├── config.py
├── poetry.lock
├── poetry.toml
├── pyproject.toml
├── README.md
├── scripts
│ ├── fix.sh
│ ├── run.sh
│ └── setup.sh
├── setup.cfg
└── wsgi.py
For the complete demo implementation, please refer to github .
implementation details
In order to implement the sub-application, we need to implement the following key functions.
- Create a blueprint of the basic application
- Register the blueprint of the base app in Flask
- Associate Dash with the base application and define routes and layouts
Create a blueprint of the basic application:
Blueprint is a component that Flask uses to implement modular applications.
app/views.py
from flask import Blueprint, render_template
base_app = Blueprint("base_app", __name__)
@base_app.route("/")
def index():
"""Landing page."""
return render_template("index.html", top_menu_items=get_top_menu_items("/"))
Register the blueprint of the base app in Flask
In Flask, this is called the application factory mode, creating a create_app
function that returns the application object. Flask will call this function to process the request.
app/__init__.py
from flask import Flask
from app.views import base_app
def create_app(test_config=None):
"""Create and configure Flask app"""
app = Flask(__name__)
app.register_blueprint(base_app)
return app
Associate Dash with the base application and define routes and layouts
Create a Dash application that uses the base application.
app/dash_apps/__init__.py
def customize_index_string(app, url):
"""Custom app's index string"""
app.index_string = env.get_template("dash_layout.html").render(
top_menu_items=get_top_menu_items(url)
)
def add_route(app, url):
"""Add route to the app"""
app.server.add_url_rule(url, endpoint=url, view_func=app.index)
app.routes.append(url)
def create_dash_app(server, url_rule, url_base_pathname):
"""Create a Dash app with customized index layout
:param server: base Flask app
:param url_rule: url rule as endpoint in base Flask app
:param url_base_pathname: url base pathname used as dash internal route prefix
"""
app = dash.Dash(name=__name__, server=server, url_base_pathname=url_base_pathname)
customize_index_string(app, url_rule)
add_route(app, url_rule)
return app
app/dash_apps/custom_dash_app.py
from app.dash_apps import create_dash_app
# endpoint of this page
URL_RULE = "/custom-app"
# dash internal route prefix, must be start and end with "/"
URL_BASE_PATHNAME = "/dash/custom-app/"
def create_dash(server):
"""Create a Dash view"""
app = create_dash_app(server, URL_RULE, URL_BASE_PATHNAME)
# dash app definitions goes here
...
return app.server
How to add more Dash apps to the base app
Adding Dash to the base application requires a total of 2 steps.
Step 1: Create a Dash application
1-1: Create a .py
file in the app/dash_apps
directory.
1-2: Create a Dash application according to the following code structure.
from app.dash_apps import create_dash_app
# endpoint of this page
URL_RULE = "/custom-app"
# dash internal route prefix, must be start and end with "/"
URL_BASE_PATHNAME = "/dash/custom-app/"
def create_dash(server):
"""Create a Dash view"""
app = create_dash_app(server, URL_RULE, URL_BASE_PATHNAME)
# dash app definitions goes here, same as what you would do in normal Dash application
...
return app.server
Step 2: Add main page navigation menu for Dash application at app/views.py
(optional)
top_menus = [
{"path": "/", "title": "Home"},
{"path": "/experiments", "title": "Experiments"},
{"path": "/custom-app", "title": "Custom App"},
...
]
how to run
Execute the following script to start the application, if FLASK_ENV=development
is set, the application will run in development mode.
#!/bin/bash
source .venv/bin/activate
if [[ "${FLASK_ENV}" == "development" ]]; then
flask run --host=0.0.0.0 --port 8050
else
gunicorn wsgi:app \
--bind 0.0.0.0:8050 \
--log-level debug \
--workers 2 \
--threads 4
fi
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。