【发布时间】:2016-03-09 13:30:06
【问题描述】:
我有一个包含 QuerySelectMultipleField 的表单(WTForms via Flask-WTF),如下所示:
class EditDocumentForm(Form):
# other fields omitted for brevity
users = QuerySelectMultipleField('Select Users',
query_factory=User.query.all,
get_label=lambda u: u.username)
这很好用——我只是实例化表单并将它传递给我的模板进行渲染,所有正确的选择都在那里。
但是,当我 POST 表单并尝试使用 Form.populate_obj() 提取数据时,我收到了来自 SQLAlchemy 的愤怒消息:
InvalidRequestError: Object '<User at 0x10a4d33d0>' is already attached to session '1' (this is '3')
视图函数:
@app.route("/document/edit/<doc_id>", methods=['GET', 'POST'])
@login_required
def edit_document(doc_id):
doc = Document.query.filter_by(id=doc_id).first()
if (doc is not None) and (doc.user_id == current_user.id):
form = EditDocumentForm(obj=doc)
if request.method == "POST":
if form.validate():
form.populate_obj(doc)
db.session.commit()
return redirect('/')
else:
_flash_validation_errors(form)
return render_template("edit.html", form=form)
flash("The document you requested doesn't exist, or you don't have permission to access it.", "error")
return(redirect('/'))
所以看起来在创建表单时使用了一个会话,而当我尝试填充我的模型对象时使用了另一个会话。这一切都发生在幕后,因为我依靠 Flask-SQLAlchemy 为我做所有的会话工作。
在Document 模型中,user 字段是这样声明的:
users = db.relationship('User',
secondary=shares,
backref=db.backref('shared_docs', lazy='dynamic'))
(当然shares 是SQLAlchemy.table 的一个实例,用于多对多关系)。
那么:是我做错了什么,还是Form.populate_obj() 有问题,或者我可以责怪外星人?让我换个说法:我做错了什么?
编辑
解决方法this answer 似乎解决了这个问题,即通过导入我的 SQLAlchemy 对象并显式使用其会话来更改我的query_factory:
query_factory=lambda: db.session.query(User)
不过,我不得不说,这对我来说有一种奇怪的气味。这真的是最好的处理方式吗?
【问题讨论】:
标签: python flask flask-sqlalchemy flask-wtforms