因此,在发生bad_request,未授权,禁止或not_found之类的HTTP错误的情况下,我试图回滚数据库会话。
这是一个具有wsgi和flask的无服务器应用程序。
场景是:我创建了一个要保存在数据库中的条目,但是如果发生错误,我希望它回滚会话。
如果引发异常,则会发生回滚,但是如果我使用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响应,则会调用该函数。该中止功能会引发一个HTTPException,而该功能将被拆解功能忽略
def badrequest(message='bad request.', **kwargs):
abort(make_response(jsonify(message=message, **kwargs), 400))
我也希望teardown_appcontext也能识别HTTPException,而不仅仅是一个Exception。这样,如果调用中止函数,则将完成回滚。
答案 0 :(得分:1)
我认为这是因为teardown_appcontext
called when the request context is popped。 exception
的上下文中有一个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
之后,您将看到“坏节点”没有保存(已回滚)。
希望这会有所帮助。