Mutiple Dashboards Created On-The-Fly

Here’s what I’m trying to do:

I want to be able to make multiple dashboards dynamically and server them on different URLs. I’ve made a quick sample code to illustrate:

from flask import Flask
import dash
import dash_html_components as html

application = Flask(__name__)


def make_dash(name):
    app = dash.Dash(
        name=f'{name}',
        server=application,
        sharing=True,
        url_base_pathname=f'/{name}/'
    )
    app.layout = html.Div(f'Hello World {name}')
    return app


app1 = make_dash('app1')
app2 = make_dash('app2')


if __name__ == '__main__':
    application.run(debug=True, port=8050, host='0.0.0.0')

The output from this is:

AssertionError: A name collision occurred between blueprints <flask.blueprints.Blueprint object at 0x7fa7dfa688d0> and <flask.blueprints.Blueprint object at 0x7fa7df5ba898>. Both share the same name "assets". Blueprints that are created on the fly need unique names.

I get the same exception when trying to serve it with gunicorn.

I’ve read through https://community.plotly.com/t/dash-on-multi-page-site-app-route-flask-to-dash/, but it seems like having a layout generated on the fly isn’t good enough, because my dynamically generated dashboards will have share element names.

I’ve also tried using werkzeug.wsgi.DispatcherMiddleware', but when I do that, the various _dash-* files still try to get served from the root of my server and they can’t be found.

Is there some way to make this work?

I don’t recommend using multiple instances of dash for multiple urls. Instead, I recommend using Dash’s built-in URL handling: https://dash.plot.ly/urls. This will allow you to serve layouts with dynamic urls.

Is there some way for each of the dashboards served using that paradigm to have its own set of callbacks? I generate callbacks on the fly as well…

Yeah, each file can have it’s own callbacks, they just need to share the same app instance and the ids need to be unique universally. This is the pattern that i’ve used in several large multi page apps for clients.

I’m messing about right now and I can get the above code to work if I modify dash.Dash a little bit:

self.server.register_blueprint(
            flask.Blueprint(f'assets_{name}', 'assets',
                            static_folder=self._assets_folder,
                            static_url_path=assets_url_path))

and

            elif 'asset_path' in resource:
                static_url = flask.url_for(f'assets_{self.name}.static',
                                           filename=resource['asset_path'])
                srcs.append(static_url)

Doing this doesn’t allow sharing asset folders, which would be nice, but it does seem to allow serving 2 Dash apps from the same Flask() instance without using DispatcherMiddleware. Maybe someone more familiar with Dash internals could make a more elegant fix.

Is there some reason this is a bad idea? The idea of using unique names for all my generated ids seems cumbersome.