【问题标题】:How to access Flask app's context from within embedded Dash app when using app factory pattern?使用应用程序工厂模式时,如何从嵌入式 Dash 应用程序中访问 Flask 应用程序的上下文?
【发布时间】:2019-11-07 07:11:00
【问题描述】:

我正在使用 Flask 和 Dash 构建一个 Web 应用程序。主要的 Flask 应用程序处理用户登录和身份验证,并保护 Dash 应用程序的路由。 Dash 应用由 Flask 应用提供。

主要的 Flask 应用程序是使用 Flask Mega 教程示例 (https://github.com/miguelgrinberg/microblog) 构建的,具有应用程序工厂模式。我删除了除登录/身份验证之外的所有内容,并且该应用在那个阶段运行良好。

然后我按照此处的示例在 Flask 应用程序中添加了一个简单的 Dash 应用程序:https://github.com/okomarov/dash_on_flask。可以在 /dashboard 访问 Dash 应用程序,并且仪表板受到适当保护以防止未经授权的访问,并按预期重定向回主 Flask 登录页面。

我现在的挑战是从 Dash 应用程序中访问 Flask 应用程序的上下文和其他内容,例如数据库会话。这样 Dash 应用就可以访问和显示来自主数据库的信息。

我目前一直在尝试遵循我在网上找到的示例,以及如何使它们适应我的应用程序的特定模式。

我已尝试按照此处链接的示例进行操作:https://github.com/plotly/dash/issues/214#issuecomment-391223557。

但是,这些示例似乎都基于平面应用程序结构,其中 Flask 和 Dash 应用程序是在同一个文件中创建的。

我所有的代码都在这里:https://github.com/danielcopelin/dacy-budget

目前,我的主要 Flask 应用程序如下所示:

dacybudget.py

from app import create_app, db
from app.models import User

app = create_app()


@app.shell_context_processor
def make_shell_context():
    return {'db': db, 'User': User}

create_app() 看起来像:

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    register_dashapps(app)

    db.init_app(app)
    migrate.init_app(app, db)
    login.init_app(app)
    mail.init_app(app)
    bootstrap.init_app(app)

... 和 register_dashapps() 看起来像:

def register_dashapps(app):
    from app.dashapp1.layout import layout
    from app.dashapp1.callbacks import register_callbacks

    # Meta tags for viewport responsiveness
    meta_viewport = {
        "name": "viewport",
        "content": "width=device-width, initial-scale=1, shrink-to-fit=no",
    }
    external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
    dashapp1 = dash.Dash(
        __name__,
        server=app,
        url_base_pathname="/dashboard/",
        assets_folder=get_root_path(__name__) + "/dashboard/assets/",
        meta_tags=[meta_viewport],
        external_stylesheets=external_stylesheets,
    )

    dashapp1.title = "Dashapp 1"
    dashapp1.layout = layout
    dashapp1.url_base_pathname = "/dashboard/"  # I dont know why I had to do this
    register_callbacks(dashapp1)
    _protect_dashviews(dashapp1)

从 app.dashapp1.layout 和 app.dashapp1.callbacks 我希望能够访问主 Flask 应用程序的会话和数据库等。

如果我尝试从 app.dashapp1.layout 中进行各种导入,例如“from .. import db”,然后尝试对该 db 对象执行某些操作,则会收到如下错误:

RuntimeError:未找到应用程序。在视图函数中工作或推送应用程序上下文。见http://flask-sqlalchemy.pocoo.org/contexts/。

有人可以就如何解决这个问题提供任何建议吗?

【问题讨论】:

  • 将参数的名称从register_dashapps,从app更改为server,将代码函数修改为更改名称,并进行测试。我认为这是参数和包名之间的名称冲突。

标签: python-3.x flask flask-sqlalchemy plotly-dash


【解决方案1】:

我设法解决了我的问题。我一直在努力了解应用程序的 Dash 端的哪个位置可以访问主 Flask 应用程序的上下文,以便我可以为 Dash 提供对数据库的访问权限。事实证明,这可以在 register_callbacks() 函数中完成,其中定义的实际回调函数如下所示:

def register_callbacks(app):
    from app import db
    from app.models import Transaction
    ...

    @app.callback(
        Output("main", "children"),
        [Input("transaction_table", "data_previous")],
        [
            State("transaction_table", "data"),
            State("transaction_table", "page_current"),
        ],
    )
    def update_database_and_generate_table(old_table_data, table_data, page_current):
        with app.server.app_context():
            if old_table_data is not None:
                update_changed_data(old_table_data, table_data)
            transactions = db.session.query(Transaction)
            df = pd.read_sql(transactions.statement, transactions.session.bind)

为此,必须对我最初问题的代码进行另一项更改。在create_app()函数中,需要在数据库初始化完成后注册Dash应用:

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    db.init_app(app)
    migrate.init_app(app, db)
    login.init_app(app)
    mail.init_app(app)
    bootstrap.init_app(app)

    app = dashapp.add_dash(app)
    ...

完整的工作示例位于此处:https://github.com/danielcopelin/dacy-budget

【讨论】:

【解决方案2】:

您的答案在这里Project Layout。 我遇到了类似的问题,无法在烧瓶应用程序中执行“正常”python 导入。

按照建议将您的应用命名为 flaskr,然后将 app.py 和 templates 移到那里......就像在教程中一样。它对我有用。

【讨论】:

    猜你喜欢
    • 2020-09-26
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 2020-09-04
    • 2018-02-01
    • 2020-12-17
    • 1970-01-01
    相关资源
    最近更新 更多