flask-wtf 使用wtform构造器编辑模型:预填充表单

1 投票
1 回答
3651 浏览
提问于 2025-04-18 13:51

我正在阅读《Flask Web Development》这本书,遇到了以下内容:

def edit_profile():
    form = EditProfileForm()
    if form.validate_on_submit():
        current_user.name = form.name.data
        current_user.location = form.location.data
        current_user.about_me = form.about_me.data
        db.session.add(user)
        flash('Your profile has been updated.')
        return redirect(url_for('.user', username=current_user.username))
    form.name.data = current_user.name
    form.location.data = current_user.location
    form.about_me.data = current_user.about_me
    return render_template('edit_profile.html', form=form)

简单来说,当表单没有提交或者没有通过验证时,这段代码会把当前用户的数据复制过来。然后我在研究wtforms时,看到关于表单的init方法有这样的说明:

obj – If formdata is empty or not provided, this object is checked for attributes
      matching form field names, which will be used for field values.

所以我想这意味着我们可以这样写(下面的例子是我自己写的):

def edit_post(post_id):
    post = Post.query.get_or_404(post_id)
    if current_user != post.author:
        abort(403)
    # Below is the line I am concerned about
    form = PostForm(formdata=request.form, obj=post)
    if form.validate_on_submit():
        form.populate_obj(post)
        db.session.commit()
        return redirect(url_for('user', username=current_user.username))
    return render_template('post_form.html', form=form)

我认为这应该在GET请求时从数据库模型填充表单实例,而在POST请求后从提交的数据填充。测试了一下,似乎是有效的……

现在我的问题是:这样写编辑视图是否正确?还是应该像书里说的那样,一个字段一个字段地复制?

1 个回答

1

在处理POST请求时,使用MultiDict来加载数据是将键值对映射到你的WTForms实例的标准方法。如果你使用Flask-WTF这个扩展,它会自动为你完成这个过程,这就是这个扩展的一个好处。

如果你查看Flask-WTF的代码,会发现它继承了WTForms的SecureForm类,并默认尝试加载Werkzeug的POST MultiDict(叫做formdata),前提是这个数据存在。所以在你的视图中像这样加载表单:

form = PostForm(obj=post)

如果使用Flask-WTF,这样做就足够了,还能自动填充POST请求中的数据到表单字段。

书中示例中的做法当然没有错,但会产生很多不必要的代码,并且容易出错或重复——你可能会忘记在视图中提到WTForms实例中声明的某个字段。

撰写回答