xav*_*xav 4 python pytest flask flask-sqlalchemy
我正在为pytest配置一个fixture来创建一个烧瓶app实例.我的应用程序是使用Application Factories模式创建的.我正处于将其连接到数据库的阶段,并且很难理解2种模式之间的区别.
# project/__init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app_settings = os.getenv('APP_SETTINGS')
app.config.from_object(app_settings)
db.init_app(app)
[blueprint code]
return app
Run Code Online (Sandbox Code Playgroud)
在我的夹具中,我想我理解需要:
db.create_all() 在安装过程中:创建我的表格db.drop_all() 拆解期间:测试后清理数据库db.session.remove() 在拆解过程中:在测试中频繁访问数据库时,请避免使用postgres上的一些奇怪锁定第一个设置(灵感来自Miguel Grinberg的书)对我有意义:
import pytest
from project import create_app, db
@pytest.fixture
def app():
app = create_app()
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
Run Code Online (Sandbox Code Playgroud)
它还匹配我在交互式会话中获得的行为,我需要激活/推送app_context绑定数据库:
Python 3.6.1 (default, Jun 21 2017, 18:45:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from project import create_app, db
>>> app = create_app()
>>> db
<SQLAlchemy engine=None>
>>> app_ctx = app.app_context()
>>> app_ctx.push()
>>> db.create_all()
>>> db
<SQLAlchemy engine='postgres://postgres:postgres@users-db:5432/users_dev'>
Run Code Online (Sandbox Code Playgroud)
第二个设置(灵感来自testdriven.io)也可以在pytest中工作,但我不知道为什么:
import pytest
from project import create_app, db
@pytest.fixture
def app():
app = create_app()
db.create_all()
db.session.commit() # fail when this is removed
yield app
db.session.remove()
db.drop_all()
Run Code Online (Sandbox Code Playgroud)
实际上,如果我尝试在交互式会话中执行相同操作,则会收到错误消息:
Python 3.6.1 (default, Jun 21 2017, 18:45:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from project import create_app, db
>>> app = create_app()
>>> db.create_all()
[...] timeError: application not registered on db instance and no application bound to current context
Run Code Online (Sandbox Code Playgroud)
我试图在没有的情况下运行灯具db.session.commit(),认为我可能默认在应用程序上下文中(类似于我with app_context()在第一个灯具中执行的操作).但是如果我删除它就会失败.
第一个问题是,第二设置(通过testdriven.io)不使用应用程序工厂模式,是通过明确实例数据库,并结合应用(例如,db = SQLAlchemy(app)与db = SQLAlchemy()和以后db.init(app)的create_app()).如果您使用的是Application Factory模式,则会在执行后获得您在交互式会话中看到的错误db.create_all(),保留/删除db.session.commit()无论如何都无济于事.
我有一个暗示,你from project import create_app, db为每次尝试使用两种不同的方法,并使用Application Factory模式进行交互式shell.
无论如何,你真的在问两个问题.
1)为什么db.create_all()在使用Application Factory模式时需要推送应用程序上下文才能运行?
如果你在寻找__init__方法SQLAlchemy,你会发现,你可以通过一个应用程序,在这种情况下,该应用程序变得绑定到SQLAlchemy的对象self.app = app.但是,因为您正在使用Application Factory模式,所以即使在您运行之后,该应用也从未明确绑定db.init_app(app).现在看一下create_all(),它需要一个可选的app,你没有通过,所以当我们到达时get_app,我们跳过reference_app它None,因为它是,我们过去current_app,看看Flask的应用程序上下文(请参阅参考资料from flask import current_app),如果你没有推上下文,这也将是None,最后我们检查是否有self.app,但这也是None因为我们正在使用Application Factory模式,因此application not registered on db instance and no application bound to current context错误.
2)为什么在SQLAlchemy实例化期间绑定应用程序时运行db.session.commit()后需要显式运行db.create_all(例如db = SQLAlchemy(app))?**
我似乎无法重现这个错误,我在下面添加了一个代码块来向您展示我正在使用的内容,我从testdriven.io网站上获得了这些内容.但是,您不应该这样做db.session.commit(),使用Application Factory模式和使用应用程序实例化SQLAlchemy(例如db = SQLAlchemy(app))之间的唯一区别是,使用前者,您需要传入应用程序create_all(app)或推送应用程序上下文.
import pytest
import os
import datetime
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
@pytest.fixture
def app():
app = create_app()
db.create_all()
# db.session.commit() # Try this with and without this line
yield app
db.session.remove()
db.drop_all()
Run Code Online (Sandbox Code Playgroud)
参考文献:
http://flask-sqlalchemy.pocoo.org/2.1/contexts/
| 归档时间: |
|
| 查看次数: |
1073 次 |
| 最近记录: |