teardown_appcontext是否忽略HTTPExceptions?

时间:2019-05-21 14:13:09

标签: python flask wsgi serverless

因此,在发生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。这样,如果调用中止函数,则将完成回滚。

1 个答案:

答案 0 :(得分:1)

我认为这是因为teardown_appcontext called when the request context is poppedexception的上下文中有一个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之后,您将看到“坏节点”没有保存(已回滚)。

希望这会有所帮助。