Example: Creating Multi-Page and Custom-Page apps at layout time

I have spent some time playing around with different multi-page approaches. I thought I would share this one as it seems useful to other people.

Firstly this is just an extension of https://dash.plot.ly/urls and doesn’t provide any completely new functionality. But sometimes you want to directly load the layout without waiting for some multi-page callback to kick in, here are examples of doing that:

For those times try this approach based on the Referer URL:

# Standard Libary
from urllib.parse import urlparse

# Third Party Libraries
import dash
import flask
import dash_html_components as html


def serve_layouts(layout_dict):
    def serve_layouts_closure():
        if not flask.has_request_context():
            return html.Div()

        referer = flask.request.headers.get('Referer', '')
        path = urlparse(referer).path
        pages = path.split('/')

        if len(pages) < 2 or not pages[1]:
            return html.Div('Root Page')

        page = pages[1]
        if page in layout_dict:
            return layout_dict[page]

        return html.Div('Nothing here but us chickens')
    return serve_layouts_closure


server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server)
app.config.supress_callback_exceptions = True

page_one_layout = html.Div('Hello World')
page_two_layout = html.Div('Hello World!!', style={'font-weight': 'bold'})
secret_layout = html.Div('Ssshhhh, this is a secret easter egg')

app.layout = serve_layouts({'page1': page_one_layout,
                            'page2': page_two_layout,
                            'secret': secret_layout})


if __name__ == '__main__':
    app.run_server()

With this script try visiting:

  1. http://127.0.0.1:8050
  2. http://127.0.0.1:8050/page1
  3. http://127.0.0.1:8050/page2
  4. http://127.0.0.1:8050/secret
  5. http://127.0.0.1:8050/foo

Now instead of parsing out the page from the Referer URL we could also parse out a query string and produce a custom page based on that query string (this is something I do quite often).

Here’s how you would get started:

# Standard Libary
from urllib.parse import urlparse, parse_qs

# Third Party Libraries
import dash
import flask
import dash_html_components as html


def serve_layout():
    if not flask.has_request_context():
        return html.Div()

    query = ''
    referer = flask.request.headers.get('Referer')
    if referer:
        query_string = urlparse(referer).query
        if query_string:
            query = parse_qs(query_string)

    return html.Div(f'Your query was: {query}')


server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server)
app.config.supress_callback_exceptions = True
app.layout = serve_layout


if __name__ == '__main__':
    app.run_server()

With this example try going to http://127.0.0.1:8050/?page=custom&option=foo

Again all of this can be achieved with callbacks and dcc.Link, but with this approaches the custom page is served at layout time. Hope it helps someone!

3 Likes