【问题标题】:Flask app context for sqlalchemysqlalchemy 的烧瓶应用程序上下文
【发布时间】:2016-04-12 17:01:50
【问题描述】:

我正在烧瓶中开发一个小的休息 api。 Api 具有注册请求并生成单独线程以在后台运行的路由。代码如下:

def dostuff(scriptname):
    new_thread = threading.Thread(target=executescript,args=(scriptname,))
    new_thread.start()

线程启动,但当我尝试从 executescript 函数插入 db 时出错。它抱怨未在应用程序中注册的 db 对象。

我正在动态创建我的应用(使用 api 作为蓝图)。

这是应用程序的结构

-run.py ## runner script
-config
   -development.py
   -prod.py
-app
  -__init__.py
  - auth.py
  - api_v1
     - __init__.py
     - routes.py
     - models.py

这是我的运行脚本run.py

from app import create_app, db

if __name__ == '__main__':
    app = create_app(os.environ.get('FLASK_CONFIG', 'development'))
    with app.app_context():
        db.create_all()
    app.run()

这是来自app/__init__.py 的代码,它创建了应用程序:

from flask import Flask, jsonify, g
from flask.ext.sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app(config_name):
    """Create an application instance."""
    app = Flask(__name__)

    # apply configuration
    cfg = os.path.join(os.getcwd(), 'config', config_name + '.py')
    app.config.from_pyfile(cfg)

    # initialize extensions
    db.init_app(app)
    # register blueprints
    from .api_v1 import api as api_blueprint
    app.register_blueprint(api_blueprint, url_prefix='/api/')
    return app 

我只需要知道如何在routes.py 中扩展应用上下文。我不能直接在那里导入应用程序,如果我执行以下操作,我会得到RuntimeError: working outside of application context

def executescript(scriptname):
    with current_app.app_context():
        test_run = Testrun(pid=989, exit_status=988,comments="Test TestStarted")
        db.session.add(test_run)
        db.session.commit()

【问题讨论】:

    标签: python flask flask-sqlalchemy flask-restful


    【解决方案1】:

    您正在另一个没有应用程序上下文的线程中运行后台任务。您应该将 app 对象传递给后台工作人员。 Miguel Grinberg gives an example of this here:

    from threading import Thread
    from app import app
    
    def send_async_email(app, msg):
        with app.app_context():
            mail.send(msg)
    
    def send_email(subject, sender, recipients, text_body, html_body):
        msg = Message(subject, sender=sender, recipients=recipients)
        msg.body = text_body
        msg.html = html_body
        thr = Thread(target=send_async_email, args=[app, msg])
        thr.start()
    

    或者(可能是最好的解决方案)实际上是set up a thread-local scoped SQLAlchemy session,而不是依赖于 Flask-SQLAlchemy 的请求上下文。

    >>> from sqlalchemy.orm import scoped_session
    >>> from sqlalchemy.orm import sessionmaker
    
    >>> session_factory = sessionmaker(bind=some_engine)
    >>> Session = scoped_session(session_factory)
    

    【讨论】:

    • 我喜欢线程本地 sqlalchmey 会话。会努力的。谢谢!
    • 如果它对您有用,请随时接受答案:)
    • 我正在使用烧瓶应用程序工厂来设置我的应用程序。这样做的缺点之一是您无法在 api 中导入应用程序。因此,sqlalchemy 线程本地会话是唯一的选择并且到目前为止有效。谢谢 Jumbopap!
    • 如果您使用应用程序工厂模式,您可以传递flask.current_app._get_current_object() 而不是app。见docsdiscussion
    猜你喜欢
    • 1970-01-01
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 2012-12-29
    相关资源
    最近更新 更多