application not registered on db

本网站用的阿里云ECS,推荐大家用。自己搞个学习研究也不错

前言

我在用Flask开发的时候,打算写个脚本用作cron定时执行。打算直接用flask中的model和sqlalchemy,并且有些代码可能会在应用中用到。代码终于写完了。。然后得到了错误”RuntimeError(‘application not registered on db ‘” and RuntimeError: application not registered on db instance and no application bound to current context。找到下面的文章

原文链接:http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/

下面是翻译。

我最近正在重构我的Flask应用,并且其中一个最重要的改变是我用到了应用工厂模式。你可以发现很多不同(但类似)使用SQLAlchemy的语法结构。这里是其中一个最常见的:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
    app = Flask(__name__)
    db.init_app(app)
    db.create_all()
    return app

然而,你应该偶然发现这么一个异常:

RuntimeError: application not registered on db instance and no application bound to current context

也许在你的测试用例中,使用db.create_all()期间。

文档并没有对此问题有清楚的描述。经过漫长的寻找,我终于发现有三个办法可以解决此问题。

方法一

创建你的db对象,并作为app的一个参数:

def create_app():
    app = Flask(__name__)
    db = SQLAlchemy(app)
    db.create_all()
    return app

缺点是你没有一个全局的db对象,并且导致你的蓝本无法工作。你将无法容易的创建models。

(顺便说:设置global db加上db = SQLAlchemy(app),对我来说没有效果)

方法二

db.app分配创建好的应用:

db = SQLAlchemy()
def create_app():
    app = Flask(__name__)
    db.init_app()
    db.app = app
    db.create_all()
    return app

这个方法的缺点是:你可能会破坏db内部源码。你不想这么做对吧?

(译者注:我是用这个办法解决了在脚本调用db的问题。并且实际上这并不会破坏内部源码。)

方法三

在应用上下文里面调用db.create_all()(这就是我们问题的所在)

db = SQLAlchemy()
def create_app():
    app = Flask(__name__)
    db.init_app(app)
    with app.test_request_context():
        db.create_all()
    return app

缺点是:这是test_request_context(test!)。但是,毕竟,它对我来说很有效果,我的所有测试用例都通过了!

用你想用的方法。

如果你遇到了问题,并且用了不同的方法解决,请评论让我知道。

额外的提示

你需要在db.create_all发生之前导入models本身:

with app.test_request_context():
    from application.models import Post
    db.create_all()

那么保持你的SQLAlchemy对象实例放在不同的文件里,以皮面不会循环导入,是一个很好的主意:

# application/database.py
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()

# application factory
from application.database import db
def create_app():
    ...
    db.init_app(app)
    ...

# application/models.py
from application.database import db
class Post(db.Model):
    ...

博主后话

以上是翻译全文,后来我在查看db.init_app()源码的时候,找到了get_app函数,发现里面抛出的异常和译文描述的是一样的信息。说明异常是在这里抛出。

    def get_app(self, reference_app=None):
        """Helper method that implements the logic to look up an application.
        """
        if reference_app is not None:
            return reference_app
        if self.app is not None:
            return self.app
        ctx = connection_stack.top
        if ctx is not None:
            return ctx.app
        raise RuntimeError('application not registered on db '
                           'instance and no application bound '
                           'to current context')

但是对于我来说,问题还是没有解决,因为我不是为了测试,事实上我的测试代码没有问题,我就是想在开发环境中测试一下。可以用原文中的方法二。但应该有更好的办法。
在stackoverflow中找到下面的答案:

This has to do with Flask’s application context. When initialized with db.init_app(app), Flask-SQLAlchemy doesn’t know which app is the “current” app (remember, Flask allows for multiple apps in the same interpreter). You could have multiple apps using the same SQLAlchemy instance in the same process, and Flask-SQLAlchemy would need to know which is the “current” one (due to Flask’s context local nature of everything).

If you need to do this during runtime, you must explicitly say which app is the “current” app for all calls. You can do this by changing your code to do the following:

def create_app():
    app = flask.Flask("app")
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
    app.register_blueprint(api)
    db.init_app(app)
    with app.app_context():
        # Extensions like Flask-SQLAlchemy now know what the "current" app
        # is while within this block. Therefore, you can now run........
        db.create_all()

    return app

If you are writing a standalone script that needs the app context, you can push the context at the beginning rather than putting everything in a with block.

create_app().app_context().push()

If you write a command for Flask’s cli the command will automatically have access to the context.

他的方法二感觉就是我想要的,但不是很明白。

我加了也没有用。

app_ctx = app.app_context()
app_ctx.push()
stocks.main()#这里有数据库的读写操作。
app_ctx.pop()

实验来实验去都没有解决掉问题。暂时妥协了。也用了原作者的方法:

db.app = app#单独的任务,这么用也没啥问题。
stocks.main()#这里有数据库的读写操作。

未经允许不得转载:演道网 » application not registered on db

赞 (1)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册