使用来自 SQLAlchemy 对象的数据在烧瓶中预填充 WTforms

Posted

技术标签:

【中文标题】使用来自 SQLAlchemy 对象的数据在烧瓶中预填充 WTforms【英文标题】:Pre-Populate a WTforms in flask, with data from a SQLAlchemy object 【发布时间】:2014-07-05 22:50:36 【问题描述】:

我对烧瓶框架相当陌生,正在为一个门户网站创建一个编辑个人资料页面。我卡在一个点上,无法自动填写表格。

这是我的表单类:

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 %

我有一个用户类的对象。我想从该对象中预填充此表单。如何预填充表单中的值。我正在尝试在这里实现编辑配置文件功能。

【问题讨论】:

【参考方案1】:

您需要在创建对象时将其传递给表单。

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()

【讨论】:

我还是有点迷茫。一旦我以表单发送我的用户对象,我认为我还需要编辑模板,否则它将如何将正确的字段与模型相关联?由于我的用户模型和表单类中的数据成员具有不同的名称。 为什么它们不同?另外,你能给我们看看模型吗? github.com/hammadhaleem/fedora-college/blob/develop/… 这是我的模型。 根据您上面的EditProfile 表单和您在 GitHub 上的代码,这些字段在您的用户模型和表单中具有相同的名称。 @dim 如果我不需要填充表单中的所有数据,populate_obj 将尝试批量分配所有表单字段但我只想批量分配一些表单【参考方案2】:

我发现的最简单的方法是在获取请求中填写表单字段。

@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 的回答提出了一些正确的做法。

【讨论】:

【参考方案3】:

要使用 SQLAlchemy 对象填充表单,请使用:

form = EditProfile(obj=<SQLAlchemy_object>)

如果您的表单字段由于某种原因(它们应该)与模型中的数据库列不匹配,则表单类将采用 kwargs:

**kwargs – 如果 formdata 或 obj 都不包含字段的值,则表单会将匹配关键字参数的值分配给 字段(如果提供)。

我发现一个用例是,如果您的表单包含引用多个模型的字段(例如,通过关系);通过obj 是不够的。

因此,让我们以您的示例为例,在您的数据库模型(对于user)中,您使用site 而不是website(表单字段名称)。您可以这样做以从 SQLAlchemy 对象填充您的表单:

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

然后在 POST 中,您必须这样做才能从表单中填充 SQLAchemy 对象:

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

【讨论】:

如何重新填充 MultiSelectField ?我不是要使用 obj,我想使用字段名但它对我不起作用 我不知道为什么这个例子在 2020 年现在这么难找到 :^( 这是 PalletsProject 上关于 Select, Insert, Delete 的页面。几乎所有的 CRUD,但是 Update--SQLA 呢obj 到 WTForms 对象中?%^\

以上是关于使用来自 SQLAlchemy 对象的数据在烧瓶中预填充 WTforms的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 合并()不使用烧瓶工作

有没有办法在烧瓶 sqlalchemy 连接中添加 mySQL 数据库/模式名称

烧瓶-sqlalchemy 或 sqlalchemy

使用 mysql 和烧瓶登录的 Flask-sqlalchemy 损坏管道错误 32

create_engine 中的烧瓶 SQLAlchemy KeyError 'False'

按多个参数逗号值过滤烧瓶sqlalchemy postgresql