Flask-SQLAlchemy db.create_all()在应用程序上下文之外工作时会引发RuntimeError

回答 3 浏览 1.1万 2022-10-05

我最近更新了Flask-SQLAlchemy,而现在db.create_all 引发 RuntimeError: working outside of application context。我怎样才能调用create_all

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///project.db'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)

db.create_all()

这会引发以下错误:

Traceback (most recent call last):
  File "/home/david/Projects/flask-sqlalchemy/example.py", line 11, in <module>
    db.create_all()
  File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 751, in create_all
    self._call_for_binds(bind_key, "create_all")
  File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 722, in _call_for_binds
    engine = self.engines[key]
  File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 583, in engines
    app = current_app._get_current_object()  # type: ignore[attr-defined]
  File "/home/david/Projects/flask-sqlalchemy/.venv/lib/python3.10/site-packages/werkzeug/local.py", line 513, in _get_current_object
    raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.
Huzairi Haril 提问于2022-10-05
3 个回答
#1楼 已采纳
得票数 42

从Flask-SQLAlchemy 3.0开始,所有对db.engine(和db.session)的访问都需要一个活跃的Flask应用程序上下文。db.create_all使用db.engine,所以它需要一个应用程序上下文。

with app.app_context():
    db.create_all()

当Flask处理请求或运行CLI命令时,会自动推送一个上下文。你只需要在这些情况之外手动推送一个,比如在设置应用的时候。


不要在你的代码中调用 create_all,你也可以在 shell 中手动调用它。使用 flask shell 来启动一个已经有应用上下文并导入了 db 对象的 Python shell。

$ flask shell
>>> db.create_all()

如果使用普通的python shell,则可以手动推送一个上下文。

$ python
>>> from project import app, db
>>> app.app_context().push()
>>> db.create_all()
davidism 提问于2022-10-05
davidism 修改于2022-10-17
#2楼
得票数 2

我花了几个小时试图自己弄清楚这个问题。 在成功之后,我觉得我应该以身作则,做一个详细的帖子。

用下面的示例代码创建一个model.py

from flask_sqlalchemy import SQLAlchemy
import datetime
from flask_marshmallow import Marshmallow
from secret import path

database_path = path 

db = SQLAlchemy()


'''
setup_db(app)
    binds a flask application and a SQLAlchemy service
'''
def setup_db(app, database_path=database_path):
    app.config["SQLALCHEMY_DATABASE_URI"] = database_path
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
    db.app = app
    db.init_app(app)
    

'''
db_drop_and_create_all()
    drops the database tables and starts fresh
    can be used to initialize a clean database
    !!NOTE you can change the database_filename variable to have multiple verisons of a database
'''

def db_drop_and_create_all(app):
    with app.app_context():
        db.drop_all()
        db.create_all() 
  

class Articles(db.Model):
    __tablename__ = "articles"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
    body = db.Column(db.Text())
    date = db.Column(db.DateTime, default = datetime.datetime.now)
    
    
    def __init__(self, title, body):
        self.name = title
        self.body = body
    
    
    def __repr__(self):
        return f"articles(title = {title}, body = {body}, date = {date})"

model.py中注意辅助函数db_drop_and_create_all(app)

def db_drop_and_create_all(app):
    with app.app_context():
        db.drop_all()
        db.create_all()

现在,在你的server.pyapp.py(不管你选择什么名字)中,导入必要的脚本,如下所示。

from model import setup_db, Articles, db_drop_and_create_all
from flask_cors import CORS
from flask import Flask, jsonify

app = Flask(__name__)

setup_db(app)  
CORS(app)
db_drop_and_create_all(app)
  

 
@app.route('/', methods=['GET'])
def get_articles():
    return jsonify({"Hello":  "World"})



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

专业小贴士。

在这个例子中,Cors是可有可无的。

确保用pip install dependencyName来安装本练习中使用的所有依赖性。

Ajiroghene 提问于2022-11-20
#3楼
得票数 1

如果你使用python shell而不是flask shell,你可以手动推送一个上下文。flask shell将为你处理这个问题。

>>> from project import app, db
>>> app.app_context().push()
>>> db.create_all()

Flask 文档该视频中了解有关应用程序上下文的更多信息。

Yusharth Singh 提问于2022-10-12
davidism 修改于2022-10-17