在Flask中用SQLAlchemy对象数据预填充WTforms

27 投票
3 回答
44635 浏览
提问于 2025-04-18 06:51

我刚开始学习Flask框架,正在为一个网站创建一个编辑个人资料的页面。现在我遇到了一些问题,无法让表单自动填充。

这是我的表单类:

class EditProfile(Form):

    username = TextField('Username', [Required()])
    email = TextField('Email', [Required()])
    about = TextAreaField('About', [Required()])
    website = TextField('Website', [Required()])

这是我用来处理表单的函数。

def editprofile(nickname = None):
    if g.fas_user['username'] == nickname  or request.method == 'POST':
        form = EditProfile()
        form_action = url_for('profile.editprofile')
        if request.method == 'POST' and form.validate():
            if form.username.data == nickname : 
              query = EditProfile(form.username.data,
                                 form.email.data,
                                 form.about.data,
                                 form.website.data,
                                 )
              print query #debug
              db.session.add(query)
              db.session.commit()
              flash('User Updated')
              print "added"
            return(url_for('profile.editprofile'))
        return render_template('profile/add.html', form=form,
                               form_action=form_action, title="Update Profile")
    else:
        return "Unauthorised"

这是我的表单的HTML模板:

{% extends "base.html" %}
    {% block title %}
        {{ title }}
    {% endblock %}
    {% block content %}
    {% from "_formhelpers.html" import render_field %}
    <div id="Edit Profile">
        <h2>{{  title  }}</h2>
        <form method="post" action="{{ form_action }}">
            <fieldset>
                <legend></legend>
                {{ render_field(form.username) }}
                {{ render_field(form.email)}}
                {{ render_field(form.about )}}
                {{ render_field(form.website) }}
            </fieldset>
        <input type="submit" class="button" value="Save"/>
    </form>
    </div>
    {% endblock %}


我有一个用户类的对象。我想从这个对象中预先填充这个表单。请问我该怎么做才能在表单中填入这些值呢?我正在尝试实现编辑个人资料的功能。

3 个回答

13

要用你的SQLAlchemy对象来填充表单,可以这样做:

form = EditProfile(obj=<SQLAlchemy_object>)

如果你的表单字段和模型中的数据库列不匹配(其实应该匹配),表单类可以接受一些额外的参数:

**kwargs – 如果表单数据和对象都没有某个字段的值,表单会把一个匹配的关键字参数的值赋给这个字段,如果你提供了的话。

我发现这种用法的一个场景是,当你的表单包含多个模型的字段(比如通过关系引用)时,单单传一个obj是不够的。

举个例子,假设在你的数据库模型(比如user)中,你用site来代替表单字段名website。你可以这样从SQLAlchemy对象填充你的表单:

form = EditProfile(obj=user, website=user.site)

然后在提交表单时,你需要这样做才能从表单填充你的SQLAlchemy对象:

form.populate_obj(user)
user.site = form.website.data
db.session.commit()
16

我找到的最简单的方法就是在一个获取请求中填充表单字段。

@decorator_authorized_user  # This decorator should make sure the user is authorized, like @login_required from flask-login
def editprofile(nickname = None):
    # Prepare the form and user
    form = EditProfile()
    form_action = url_for('profile.editprofile')
    my_user = Users.get(...)  # get your user object or whatever you need
    if request.method == 'GET':
        form.username.data = my_user.username
        form.email.data = my_user.email
        # and on
    if form.validate_on_submit():
        # This section needs to be reworked.
        # You'll want to take the user object and set the appropriate attributes
        # to the appropriate values from the form.
        if form.username.data == nickname: 
            query = EditProfile(form.username.data,
                                form.email.data,
                                form.about.data,
                                form.website.data,
                                )
            print query #debug
            db.session.add(query)
            db.session.commit()
            flash('User Updated')
            print "added"
            return(url_for('profile.editprofile'))
    return render_template('profile/add.html', form=form,
                           form_action=form_action, title="Update Profile")

这段代码设置了一个函数,可以在获取请求时返回一个已经填好的表单。你需要重新调整一下 form.validate_on_submit 下面的部分。Dirn 的回答提到了一些正确的做法。

29

在创建表单的时候,你需要把你的对象传递给它。

form = EditProfile(obj=user)  # or whatever your object is called

你会遇到一些麻烦,因为

          query = EditProfile(form.username.data,
                             form.email.data,
                             form.about.data,
                             form.website.data,
                             )
          db.session.add(query)

这段代码会创建一个新的 EditProfile 表单实例。然后你尝试把它添加到会话中,但会话需要的是模型,而不是表单。

相反,在验证表单之后,你可以把表单里的值和对象关联起来。

form.populate_obj(user)  # or whatever your object is called

因为你的对象已经加载好了,所以你不需要再把它添加到会话中。你可以去掉 db.session.add(query) 这一行,只需要调用 db.session.commit() 就可以了。

撰写回答