【发布时间】:2017-02-22 12:59:47
【问题描述】:
这是我偶然发现的一个奇怪的错误,我不确定它为什么会发生,无论是 SQLAlchemy、Flask-SQLAlchemy 中的错误,还是我还不知道的 Python 的任何功能。
我们使用 Flask 0.11.1,Flask-SQLAlchemy 2.1 使用 PostgreSQL 作为 DBMS。
示例使用以下代码更新数据库中的数据:
entry = Entry.query.get(1)
entry.name = 'New name'
db.session.commit()
从 Flask shell 执行时,这完全可以正常工作,因此数据库配置正确。现在,我们用于更新条目的控制器稍微简化(没有验证和其他样板文件),如下所示:
def details(id):
entry = Entry.query.get(id)
if entry:
if request.method == 'POST':
form = request.form
entry.name = form['name']
db.session.commit()
flash('Updated successfully.')
return render_template('/entry/details.html', entry=entry)
else:
flash('Entry not found.')
return redirect(url_for('entry_list'))
# In the application the URLs are built dynamically, hence why this instead of @app.route
app.add_url_rule('/entry/details/<int:id>', 'entry_details', details, methods=['GET', 'POST'])
当我在 details.html 中提交表单时,我可以完美地看到更改,这意味着表单已正确提交、有效并且模型对象已更新。但是,当我重新加载页面时,更改就消失了,就好像它已被 DBMS 回滚了一样。
我已启用app.config['SQLALCHEMY_ECHO'] = True,并且在我自己的手动提交之前可以看到“ROLLBACK”。
如果我换行:
entry = Entry.query.get(id)
收件人:
entry = db.session.query(Entry).get(id)
正如https://stackoverflow.com/a/21806294/4454028 中解释的那样,它确实按预期工作,所以我猜Flask-SQLAlchemy 的Model.query 实现中存在某种错误。
但是,由于我更喜欢第一种构造,所以我对 Flask-SQLAlchemy 进行了快速修改,并重新定义了原来的 query @property:
class _QueryProperty(object):
def __init__(self, sa):
self.sa = sa
def __get__(self, obj, type):
try:
mapper = orm.class_mapper(type)
if mapper:
return type.query_class(mapper, session=self.sa.session())
except UnmappedClassError:
return None
收件人:
class _QueryProperty(object):
def __init__(self, sa):
self.sa = sa
def __get__(self, obj, type):
return self.sa.session.query(type)
其中sa 是Flask-SQLAlchemy 对象(即控制器中的db)。
现在,事情变得奇怪了:它仍然没有保存更改。代码完全相同,但 DBMS 仍在回滚我的更改。
我读到 Flask-SQLAlchemy 可以在拆卸时执行提交,并尝试添加:
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
突然之间,一切正常。问题是:为什么?
不应该只在视图完成渲染后才进行拆卸吗?为什么修改后的Entry.query 的行为与db.session.query(Entry) 不同,即使代码相同?
【问题讨论】:
标签: python postgresql flask sqlalchemy flask-sqlalchemy