【问题标题】:Reflecting different databases in Flask factory setup在 Flask 工厂设置中反映不同的数据库
【发布时间】:2019-07-04 09:56:58
【问题描述】:

我想在我的应用程序中使用 Flask 的应用程序工厂机制。我有的是我在一些蓝图中使用的数据库位置不同,所以我使用绑定来指向它们。表本身已投入生产并已在使用中,因此我需要反映它们以便在我的应用程序中使用它们。

问题是由于应用程序上下文,我无法使反射函数正常工作。我总是得到消息,我在应用程序上下文之外工作。我完全理解这一点,并且看到,db 确实在外面,但对如何参与它一无所知。

我尝试了通过 current_app 将应用程序传递给我的 models.py 的不同变体,但没有任何效果。

config.py:

class Config(object):

    #Secret key
    SECRET_KEY = 'my_very_secret_key'

    ITEMS_PER_PAGE = 25

    SQLALCHEMY_BINDS = {
        'mysql_bind': 'mysql+mysqlconnector://localhost:3306/tmpdb'
    }
    SQLALCHEMY_TRACK_MODIFICATIONS = False

main.py:

from webapp import create_app

app = create_app('config.Config')

if __name__ == '__main__':
    app.run(debug=true)

webapp/init.py:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

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

    db.init_app(app)

    from main import create_module as main_create_module
    main_create_module(app)

    return app

webapp/main/init.py:

def create_module(app):
    from .controller import blueprint
    app.register(blueprint)

webapp/main/controller.py:

from flask import Blueprint, render_template, current_app as app
from .models import db, MyTable # <-- Problem might be here ...

bluerint = Blueprint('main', __name__)

@blueprint.route('/'):
def index():
    resp = db.session.query(MyTable)\
            .db.func.count(MyTable.versions)\
            .filter(MyTable.versions =! '')\
            .group_by(MyTable.name).all()
    if resp:
        return render_template('index.html', respo=respo)
    else:
        return 'Nothing happend'

webapp/main/models.py:

from .. import db # <-- and here ...

db.reflect(bind='mysql_bind')

class MyTable(db.Model):
    __bind_key__ = 'mysql_bind'
    __table__ = db.metadata.tables['my_table']

预期的结果是让反射在不同的蓝图中工作。

【问题讨论】:

  • 你能帮我试试这个吗,我想你需要在应用程序中注册数据库。 db = SQLAlchemy(app) 而不是 db = SQLAlchemy()。注意我发现在某些情况下使用 vanilla SQLAlchemy 和烧瓶更容易。上下文和将所有内容连接在一起变得不那么痛苦了。
  • 这将是正常行为,但在工厂设置中,您宁愿采用我上面描述的方式。实际上,使用db.init_app(app)db = SQLAlchemy(app) 是一样的。在我描述的示例中,它不会产生任何影响,因为无论哪种方式,db 对象都不能在models.py 中调用,它只能在没有工厂设置的情况下使用 Flask 和 SQLAlchemy(你称之为“vanilla SQLAlchemy”)。
  • 嗯,我尝试了很多,但这件事似乎无法解决。唯一的解决方案是在 webapp/__init__.py 中跳过 create_app 并在导入时已经初始化 db。因此,它减少了头痛。好,老,普通的“香草烧瓶”。 :)
  • db.init_app(app) 行后尝试create_app() 包括db.reflect(app=app)
  • 我觉得还是可以的,但是如果你没有多个app,就没有必要使用app factory。以后可能会玩这个。

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


【解决方案1】:

得到它的工作,完整的解决方案在这里: https://github.com/researcher2/stackoverflow_56885380

我使用sqllite3进行测试,运行create_db.py脚本来设置数据库。用 debug.sh 运行烧瓶,因为最近的版本你似乎不能只在 __main__ 中使用 app.run() 了。

说明

据我了解,如果您需要在单个应用程序或多个应用程序中多次使用它们,蓝图只是一种将多个视图组合在一起的方法。您可以根据需要添加不同的路由前缀。

一个 db 对象不与蓝图相关联,它与提供配置信息的应用程序相关联。一旦进入蓝图视图,您将可以访问 db 对象,并自动提供相关的应用程序上下文。 关于 db.reflect,您需要在 create_app 中进行调用并将其传递给 app 对象(首选)或将 app 导入到意大利面条模型中。

如您所示,可以使用绑定访问多个数据库。

因此,您的蓝图将可以访问所有导入的表,并且 flask-sqlalchemy 根据绑定知道要使用哪个数据库连接。

我通常喜欢显式定义表,因此您可以在代码完成中访问 ORM 对象和字段。您是否有很多表/字段,或者您正在创建一些东西来查询表元数据以在任何模式上实现完全自动化?像模式查看器或类似的东西。

这可能对其他来此帖子的人有用: https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/

【讨论】:

    【解决方案2】:

    太棒了!非常感谢你。得到它也工作。您的提示给了我寻找另一种方法的提示:

    @blueprint.route('/')
    def index():
    
        # pushing app_context() to import MyTable
        # now I can use db.reflect() also in models.py
        with app.app_context():
            from .models import MyTable
    
        results = db.session.query(MyTable).all()
        print(results)
        for row in results:
            print (row)
            print(row.versions)
            print(row.name)
    
        if results:
            return render_template('my_table.html', results=results)
        else:
            return 'Nothing happend'
    

    然后可以在models.py中进行反射。您发布的链接真的很有帮助,不知道为什么我自己没有偶然发现它......

    不管怎样,我现在确实比以前有更多的可能性!

    干杯,伙计!

    【讨论】:

    • 太棒了!上下文相关的导入很聪明,从来没有想过。
    • 取决于您需要访问数据库的频率。在我的代码中,您可能必须在每条路线中从 models.py 导入,使用您的方法可以访问所有蓝图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-17
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    相关资源
    最近更新 更多