python - teardown_appcontext 是否忽略 HTTPExceptions?
问题描述
因此,我试图回滚数据库会话,以防发生诸如 bad_request、未授权、禁止或 not_found 之类的 HTTP 错误。
它是一个带有 wsgi 和烧瓶的无服务器应用程序。
场景是:我创建了一个要保存在数据库中的条目,但是如果发生错误,我希望它回滚会话。
如果我引发异常,则会发生回滚,但如果我使用abort(make_response(jsonify(message=message, **kwargs), 400))
HTTPException,则会引发异常,但 teardown_appcontext 会忽略它。
我也试过application.config['PRESERVE_CONTEXT_ON_EXCEPTION'] = True #and false too
,但没有解决我的问题。
在我的应用程序中:
def database(application, engine=None):
sqlalchemy_url = os.environ.get('SQLALCHEMY_URL')
set_session(sqlalchemy_url, engine=engine)
@application.teardown_appcontext
def finish_session(exception=None):
commit_session(exception)
def commit_session(exception=None):
if exception:
_dbsession.rollback()
else:
_dbsession.commit()
_dbsession.remove()
if hasattr(_engine, 'dispose'):
_engine.dispose()
在这里,如果我想返回 bad_request 响应,则调用该函数。abort 函数引发了一个 HTTPException,该异常被 teardown 函数忽略
def badrequest(message='bad request.', **kwargs):
abort(make_response(jsonify(message=message, **kwargs), 400))
我希望 teardown_appcontext 也能识别 HTTPException,而不仅仅是一个异常。这样,如果调用了 abort 函数,就会完成回滚。
解决方案
我认为这是因为teardown_appcontext
在弹出请求上下文时调用。一个exception
是 init 在request
. 您可以使用errorhandler()或register_error_handler()回滚会话。这是一个例子:
from flask import Flask, abort, jsonify
from flask_sqlalchemy import SQLAlchemy
from werkzeug.exceptions import BadRequest
app = Flask(__name__)
app.config.update(dict(SQLALCHEMY_DATABASE_URI='...'))
db = SQLAlchemy(app)
class Node(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
@app.errorhandler(BadRequest)
def handle_bad_request(e):
db.session.rollback()
return 'session has been rolled back!', 400
@app.teardown_appcontext
def finish_session(exception=None):
if not exception:
db.session.commit()
@app.route('/bad-node')
def bad():
# add into session without commit and abort(see: handle_bad_request)
db.session.add(Node(name='bad node'))
abort(400)
@app.route('/good-node')
def good():
# without exceptions - see: finish_session
db.session.add(Node(name='good node'))
return '<good node> was saved'
@app.route('/nodes')
def all_nodes():
# just list of items from db
return jsonify([i.name for i in Node.query.all()])
if __name__ == '__main__':
db.create_all()
db.session.commit()
app.run(debug=True)
打开/good-node
和/bad-node
几次。打开之后,/nodes
你会看到“坏节点”没有保存(回滚)。
希望这可以帮助。
推荐阅读
- javascript - 页面重定向时如何从 webview 获取 url?(这是一个功能组件而不是类)
- javascript - 为什么该网站不显示在 iPhone 上?
- java - 为什么我关闭活动时总是报警
- wordpress - Git 版本化的 WordPress 项目 - 为什么要忽略大多数文件?
- python - 让 ray 自动为每个任务分配一个 GPU
- html - 如何将输入文本字段设为只读
- angular - 具有角材料的多个过滤器
- .net-core - 我需要使用 htmltextwriter 或与 html textwriter 等效的东西创建动态表吗?
- django - 如何使用 Django DRF viewset.Viewsets 添加自定义操作功能?
- javascript - 需要帮助在同一页面上构建多个范围滑块,这些滑块将根据滑块的值显示不同的图像