pythonplotly-dashdash-bootstrap-componentsmulti-page-application

Dash multi-page app using DBC navigation bar


I'm trying to replicate "multi_page_example1" from https://github.com/AnnMarieW/dash-multi-page-app-demos/tree/main. This uses a drop-down menu to navigate to different pages.

However, I want to adjust the navbar options to be the standard links as in the first example here: https://dash-bootstrap-components.opensource.faculty.ai/docs/components/navbar/

A simple example is below:

Folder structure:

- app.py
- app_pages
   |-- home.py
   |-- data_upload.py
   |-- __init__.py

home.py:

import dash
from dash import html

dash.register_page(__name__, path = '/')

layout = html.Div(children=[
        html.H1(children='This is our Home page')

])

data_upload.py:

import dash
from dash import html

dash.register_page(__name__)

layout = html.Div(children=[
        html.H1(children='This is our upload page')
])

app.py:

import dash_bootstrap_components as dbc
import dash

app = dash.Dash(__name__, 
                pages_folder = "app_pages",
                use_pages = True, 
                external_stylesheets=[dbc.themes.BOOTSTRAP])

navbar = dbc.NavbarSimple(
            children=[
                dbc.NavItem(dbc.NavLink("Home", href="/home")),
                dbc.NavItem(dbc.NavLink("Data upload", href="/data_upload")),
            ],
            brand="Multipage Dash App",
            color="dark",
            dark=True,
            className="mb2",
            )

app.layout = dbc.Container(
    [navbar, dash.page_container],
    fluid = True)

if __name__ == "__main__":
    app.run_server(debug=False)

Problems:

  1. I have to run the app with "debug=False" because the server won't launch Dash otherwise.

  2. When it launches I can see the basic web app with navbar links. However, clicking between pages generates a "404 - Page not found" message. Oddly, the home page displays the normal message initially, but the 404 after clicking between links.

Where am I going wrong?

This is my first time working with bootstrap components and Dash multi-page approaches. I'm hoping to re-configure my current tabs-only Dash web app to a multi-page app with tab layouts in individual pages.


Solution

  • Here's a simple single app.py file example demonstrating a multi-page Dash web app

    For example, using the code you provide and combining it into a single file:

    Note: You can of course extend this approach with >1 files, as you wish, so long as ensuring correct modularization & importing (e.g., of the dash.Dash app object, separate page layouts, callbacks, etc.).

    Below, the layouts for the "Home" and "Data upload" pages are defined within the same file along with a callback that updates the 'page-content' container based on the current URL path via dcc.Location.

    from dash import Dash, Input, Output
    from dash import html, dcc
    
    import dash_bootstrap_components as dbc
    
    home_layout = html.Div(children=[html.H1(children="This is our Home page")])
    
    data_upload_layout = html.Div(
        children=[html.H1(children="This is our upload page")]
    )
    
    app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
    
    navbar = dbc.NavbarSimple(
        children=[
            dbc.NavItem(dbc.NavLink("Home", href="/")),
            dbc.NavItem(dbc.NavLink("Data upload", href="/data_upload")),
        ],
        brand="Multipage Dash App",
        color="dark",
        dark=True,
        className="mb-2",
    )
    
    app.layout = html.Div(
        [
            dcc.Location(id="url", refresh=False),
            navbar,
            dbc.Container(id="page-content", className="mb-4", fluid=True),
        ]
    )
    
    
    @app.callback(Output("page-content", "children"), Input("url", "pathname"))
    def display_page(pathname):
        if pathname == "/":
            return home_layout
        elif pathname == "/data_upload":
            return data_upload_layout
        else:
            return dbc.Jumbotron(
                [
                    html.H1("404: Not found", className="text-danger"),
                    html.Hr(),
                    html.P(f"The pathname {pathname} was not recognized..."),
                ]
            )
    
    
    if __name__ == "__main__":
        app.run_server(debug=True)
    
    

    ā†’ produces this app behavior:

    Video screen recording showing functionality of example demo dash app