【Flask】Flask和SQLAlchemy:init_app

30 篇文章 2 订阅

博主前言

博主在用Flask开发的时候,需要实现一个功能:定时写数据到数据库。之前采用了一个笨方法,单独写一个Python脚本文件,并且数据库表对象还要重新定义,如果Flask那边修改了数据表对象,这边的脚本也需要就改数据表对象,非常麻烦。我于是就想能不能直接用Flask里的数据表对象。可是每次在脚本里调用数据表对象都报错,加上定时任务是用了线程机制,还涉及线程安全问题等等,任务艰巨啊。但是,最后我找到了下面这篇文章,终于明白该怎么做了。

原文链接: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')

说明如果reference_appself.appctx都没有配置好,则会抛出异常!

  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值