Python Plotly Dash with Flask Login: How to properly place @callback?

I’m trying to build a Dash app in Flask following this example: openDashAuth/dashboard.py at main · seanmajorpayne/openDashAuth · GitHub

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
from app.auth import routes
from app.models import User


def create_dashboard(server):
    """Create a Plotly Dash dashboard embedded within Flask"""
    dash_app = dash.Dash(
        server=server,
        routes_pathname_prefix="/dashapp/",
        external_stylesheets=[dbc.themes.CERULEAN],
    )

    dash_app.layout = html.Div(
        children=[
            html.Div(
                [
                    html.Div(
                        [
                            html.H1(id="my-header", className="text-center"),
                        ],
                        className="col-md-12",
                    )
                ],
                className="row",
            ),
            html.A("Login", id="login-link", href="/login"),
            html.Div(id="my-div", className="text-center"),
            html.Button(
                id="submit-button-state",
                n_clicks=1,
                children="Submit",
                style={"display": "none"},
            ),
        ]
    )

    @dash_app.callback(
        [
            Output(component_id="my-header", component_property="children"),
            Output(component_id="my-div", component_property="children"),
            Output(component_id="login-link", component_property="style"),
        ],
        [Input(component_id="submit-button-state", component_property="n_clicks")],
    )
    def get_user_name(n_clicks):
        """
        The dashboard only loads if a user is authenticated
        """
        if routes.get_user().is_authenticated:
            welcome_msg = "Welcome back, " + routes.get_user().username
            user_data = load_data()
            link_style = {"display": "none"}
            return welcome_msg, user_data, link_style
        return "Your Princess is in another castle", ""

    def load_data():
        """
        The user's data is pulled from a database. As the user has already been
        authenticated, the 'current_user' from 'flask_login' is used within a database
        query, ensuring that the correct user's data is loaded. This is the key to
        having multiple user authentication with dedicated views for each user.
        """
        x = []
        y = []
        u = routes.get_user()
        data = u.data_for_user.all()
        for d in data:
            x_data = [d.x1, d.x2, d.x3]
            y_data = [d.y1, d.y2, d.y3]
        return html.Div(
            [
                html.Div(
                    [
                        dcc.Graph(
                            id="client-data",
                            figure={
                                "data": [
                                    {
                                        "x": x_data,
                                        "y": y_data,
                                        "type": "scatter",
                                        "name": "Data",
                                    }
                                ],
                                "layout": {
                                    "title": "Customer Data",
                                    "plot_bgcolor": "#252e3f",
                                    "paper_bgcolor": "#252e3f",
                                    "font": dict(color="#FFFFFF"),
                                    "xaxis": dict(
                                        title="x axis",
                                        color="#98FB98",
                                    ),
                                    "yaxis": dict(title="y axis", color="#98FB98"),
                                    "line": dict(color="#98FB98"),
                                },
                            },
                        )
                    ],
                    className="col-md-8",
                )
            ],
            className="row justify-content-center",
        )

    return dash_app.server

When I don’t use @Callback everything works and each user gets only their data after identification. The problem is that this is a static state that is not all filtered by month.

When I add @Callback with a filter, I only get the first user, and after logging out or just refreshing the page, I get a blank page.

My try:

imports...


def create_dashboard(server):
    """Create a Plotly Dash dashboard embedded within Flask"""
    dash_app = dash.Dash(
        server=server,
        routes_pathname_prefix="/dashapp/",
        external_stylesheets=[dbc.themes.CERULEAN],
    )

    dash_app.layout = html.Div(
        children=[
            html.Div(
                [
                    html.Div(
                        [
                            html.H1(id="my-header", className="text-center", style={'color': 'black', 'fontSize': 10}),
                        ],
                        className="col-md-12",
                    )
                ],
                className="row",
            ),
            html.A("Login", id="login-link", href="/login"),
            html.Div(id="my-div", className="text-center"),
            html.Button(
                id="submit-button-state",
                n_clicks=1,
                children="Submit",
                style={"display": "none"},
            ),
        ]
    )

    @dash_app.callback(
        [
            Output(component_id="my-header", component_property="children"),
            Output(component_id="my-div", component_property="children"),
            Output(component_id="login-link", component_property="style")
        ],
        [Input(component_id="submit-button-state", component_property="n_clicks")],
    )

    def get_user_name(n_clicks):
        """
        The dashboard only loads if a user is authenticated
        """
        if routes.get_user().is_authenticated:
            welcome_msg = "Welcome back, " + routes.get_user().username
            user_data = load_data()
            link_style = {"display": "none"}
            return welcome_msg, user_data, link_style
        return "Your Princess is in another castle", ""


    def load_data():
        """
        The user's data is pulled from a database. As the user has already been
        authenticated, the 'current_user' from 'flask_login' is used within a database
        query, ensuring that the correct user's data is loaded. This is the key to
        having multiple user authentication with dedicated views for each user.
        """

        u = routes.get_user()
        df = pd.DataFrame([(d.month, d.userid, d.amount) for d in u.data_for_user.all()],columns=['month', 'userid', 'amount'])
      
        # SlicerMonth
        month_Selector = dcc.Dropdown(id='Month_dropdown',
                                              options=[{'label': i, 'value': i}
                                                       for i in df.sort_values(by=['Month'], ascending=False)['Month Name'].unique()],
                                              placeholder="Select Month")


        header = html.Div([
            html.H1(df['userid'][1], style={'color': 'darkblue', 'fontSize': 20}),
            html.Div(id='object'),
            html.Div(Month_Selector, style={'width': '200px'})
        ])

        # Callbacks
        @dash_app.callback(
                    Output(component_id='object', component_property='figure'),
                    Input(component_id='Month_dropdown', component_property='value')
                )
        def update_graph(selected_month):


            filtered_df = df[df['month'] == selected_month)]
            fig = html.Div(filtered_df ['amount'].sum(), style={'color': 'darkblue', 'fontSize': 20})
            return fig

        return header
    return dash_app.server

Can’t figure out where and how to place @callback. Please help me figure out how to add a month filter using @callback and make a dynamic dashboard. Thanks !!

Hi, @Galat I think you are missing a return at get_user_name function for login-link.

    link_style = {"display": "none"}
            return welcome_msg, user_data, link_style
        return "Your Princess is in another castle", "", something_here_for_login_link

Hi @HarishOsthe,

It example works great, and every user identifies and gets a dashboard only with his data, but only in static mode.
The problem in this example is using “Low-Level Interface” in the data_load() function return.
I do not understand how to add @Callback with filters inside the dashboard when using “Low-Level Interface”.

Hi @galat I´m trying to deploy a dash app with multi users. Did you find a solution for your problem?

Hi, I just place the layout before the main @callback and all calculations based on input UserID after the main @callback, and this work.