dash_on_flask
dash_on_flask copied to clipboard
Integrate the dash app layout with templates?
Is there any way to integrate the dash app into one of the templates?
For example I may have some common elements such as a navbar
/ footer
that should also be displayed around the dash_app
. Any advice on how to do this or would we just have to duplicate that part of the HTML
code in the layout.py
?
I actually was wondering this same thing. Here's how I made it work.
The following modifies the "index_string" per this article. https://dash.plot.ly/external-resources
from flask import Flask, render_template_string
def _get_index_string(template):
"""
Replace the following 'commented-out' placeholders in my 'dash.html'
Flask template with the placeholders that Dash requires, for modifying the
'index_string' of the dash app
"""
template = template.replace(r'<!-- %metas% -->', r'{%metas%}')
template = template.replace(r'<!-- %title% -->', r'{%title%}')
template = template.replace(r'<!-- %favicon% -->', r'{%favicon%}')
template = template.replace(r'<!-- %css% -->', r'{%css%}')
template = template.replace(r'<!-- %app_entry% -->', r'{%app_entry%}')
template = template.replace(r'<!-- %config% -->', r'{%config%}')
template = template.replace(r'<!-- %scripts% -->', r'{%scripts%}}')
template = template.replace(r'<!-- %renderer% -->', r'{%renderer%}')
return template
def register_dashapps(app):
"""
Register Dash apps with the Flask app
"""
# Meta tags for viewport responsiveness
meta_viewport = {
"name": "viewport",
"content": "width=device-width, initial-scale=1, shrink-to-fit=no"
}
dashapp1 = dash.Dash(__name__,
server=app,
url_base_pathname='/dash/',
assets_folder=get_root_path(__name__) + '/assets/',
meta_tags=[meta_viewport],
)
with app.app_context():
# Render my Flask template to get a special 'index_string' for the Dash app
path = get_root_path(__name__) + "/templates/dash.html"
with open(path, 'r') as f:
template_string = render_template_string(f.read())
index_string = _get_index_string(template_string)
dashapp1.index_string = index_string
dashapp1.title = 'CHANGING THE LANDSCAPE'
dashapp1.layout = get_layout(dashapp1)
register_callbacks(dashapp1)
_protect_dashviews(dashapp1)
return app
I also needed to manually set the "SERVER_NAME" environment variable, so that flask could use the "render_template_string()" method
class BaseConfig:
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = os.environ['SECRET_KEY']
# Change this for production. Flask needs this if we use the 'render_template_string()' method
SERVER_NAME = '127.0.0.1:5000'
I hope the above is relatively self-explanatory. I assume you're way better at Flask than I am. :)
Cheers, Sean
Thanks @mccarthysean that is very insightful - I will try this as soon as possible.
@mccarthysean thanks for the contribution. I will have some time to review it next week and will add a section in the blog/template :)
Thank you @mccarthysean for the helpful advice.
One small addition I had to make was to register the dashapps after the blueprints to get commands like url_for('main.index')
in the template to work:
def create_app():
server = Flask(__name__)
server.config.from_object(BaseConfig)
register_extensions(server)
register_blueprints(server)
register_dashapps(server)
return server
I just have one issue that I cannot resolve: The base.html
in the repository uses the variable current_user
to link to either "login" or "logout". I am trying to use this logic in a navigation bar that should be displayed on all pages, also on the dashboard pages. Therefore, I import current_user
when I create the dash app and pass it as an argument to render_template_string()
:
from flask_login import current_user
.
.
.
with open(path, 'r') as f:
template_string = render_template_string(
f.read(),
current_user=current_user
)
However, the current_user
is always None
in this context, whereas, for example, on the index page it works as intended. Does anyone know a solution to that?