Using App Factory Pattern with Dash?

Consider an application_folder that has a ‘dash_application’ folder. The dash_application folder has a dash_example.py file as:

##########################
import glob
from pathlib import Path
from dash import Dash
import dash_table
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
from .layout import html_layout
from flask_login import login_required


def dash_application():
    # Create a Dash app
    dash_app = Dash(__name__, 
                    server=False, # Don't give dash a server just yet.
                    url_base_pathname='/dashapp/')
    

    # Create Dash Graph
    dash_app.layout = html.Div([
    html.H1('Dash application'),
    dcc.Graph(
        id='basic-graph',
        figure={
            'data':[
                {
                    'x': [0, 1],
                    'y': [0, 1],
                    'type': 'line'
                }
            ],
            'layout': {
                'title': 'Basic Graph'
                }
                }
            )
        ])

    return dash_app
##########################

The application_folder has __init__.py as:

#############################################
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_required
from .dash_application import dash_example


## Globally accessible libraries
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'auth_bp.login'
dash = dash_example.dash_application()



def create_app():
    # Initialize the core application.
    app = Flask(__name__, instance_relative_config=False)
    app.config.from_object('config.Config')

    # Initialize Plugins
    db.init_app(app)
    login_manager.init_app(app)
    
    # This is where a dash app attaches to a server
    dash.init_app(app=app)

    with app.app_context():
        # Set global variables


        # Include our Routes
        from . import routes
        from . import auth


        # Register Blueprints
        app.register_blueprint(auth.auth_bp)
        app.register_blueprint(routes.main_bp)

        db.create_all()

        return app
############################################

application_folder also has routes.py

###############################
import os
from flask import Blueprint, render_template, redirect, url_for
from flask_login import current_user, login_required


main_bp = Blueprint('main_bp', __name__,
                    template_folder='templates',
                    static_folder='static')


@main_bp.route('/')
@login_required
def home():
    return render_template("index.html")


@main_bp.route('/page2')
@login_required
def home2():
    return "This is page 2"
####################################

application_folder also has auth.py

###################################
import os
from flask import Blueprint, render_template, redirect, url_for, request
from flask_login import current_user, login_required, login_user, logout_user
from werkzeug.urls import url_parse


from .models import User
from .forms import LoginForm
from . import db


auth_bp = Blueprint('auth_bp', __name__,
                    template_folder='templates',
                    static_folder='static')


@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('main_bp.home'))
    
    form = LDAPLoginForm()
    if form.validate_on_submit():
        login_user(user=form.user)
        next_page = request.args.get('next')
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('main_bp.home')
        return redirect(next_page)

    return render_template('login.html', title='Sign In', form=form)

@auth_bp.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for("auth_bp.login"))
##########################################

In this setup, dash is initialized but does not attach to any server. In the create_app() function, a standalone flask app/server is created and dash gets attached to this server with the .init_app call(app). I hope this is helpful.

2 Likes