【问题标题】:Multiple WTForm fields from same form class in HTML table?HTML表中同一表单类的多个WTForm字段?
【发布时间】:2014-03-15 13:35:42
【问题描述】:

我正在努力弄清楚如何完成与表格中的另一个元素相关联的独特表单字段实例。举一个人为的例子,下面是下面的代码:

from flask import Flask, render_template, request
from flask.ext.wtf import Form
from wtforms import TextField, BooleanField

app = Flask(__name__)

app.debug = True
app.config['SECRET_KEY'] = 'secret'

class Person(Form):
    fname = TextField('First Name')
    phone = TextField('Phone Number')
    email = TextField('Email Address')
    active = BooleanField('Active')

@app.route("/", methods=['GET', 'POST'])
def guest():
    names = ['Bob', 'Joe', 'Jason', 'John'] # this could be a list, or data returned from a db query, previous POST data, or whatever
    form = Person()
    if request.method == 'POST' and form.validate_on_submit():
        return str(form.data)

    return render_template('index.html', names=names, form=form)

if __name__ == "__main__":
    app.run(host='0.0.0.0')

我的模板:

<html>
<body>
<form action="" method="post">
<table border="1">
    <thead>
        <tr>
            <th>Name</th>
            <th>Telephone Number</th>
            <th>Email Address</th>
            <th>Active</th>
        </tr>
    </thead>
    <tbody>
        {% for n in names %}
        <tr>
            <td>{{ n }}</td>
            <td>{{ form.phone }}</td>
            <td>{{ form.email }}</td>
            <td>{{ form.active }}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

很明显,在HTML中,每个表格行中每个输入元素的name参数都是相同的,因为使用的是相同的表单字段,所以“POST”,如果输入一个电话号码,那现在为表中的所有姓名行填充电话号码。 “激活”复选框也是如此。我还尝试生成表单实例列表并将该列表传递到模板中,但它似乎没有像我预期的那样工作。在这一点上,我的选择似乎是:

  1. 不要为此使用 WTForms(参见下面的注释)
  2. 使用 WTForms FieldList + FormField(我认为这也行不通,因为它们需要命名键而不是任意键,所以我会遇到完全相同的问题。)
  3. 以某种方式使用 HiddenFields(甚至没有想过这是如何工作的)。

我知道我可以通过模板手动将&lt;input type&gt; 元素创建到表中,并根据w 为它们分配不同的名称/ID,但这感觉不是很地道,而且我有自己在验证中编码。

【问题讨论】:

    标签: python flask wtforms


    【解决方案1】:

    你通常会传入一个包含表单数据的多字典对象作为表单的第一个参数:

    form = UpdateWidgetForm(request.form)
    

    这确实要求POST 数据与表单中的小部件匹配;每个小部件都将检查该多字典并使用一些预填充的数据提取它需要呈现的内容。

    或者,您可以将值作为关键字参数传递,但这需要您自己验证输入,将任何值转换为正确的类型:

    number = request.form.get('widget_number')
    try:
        number = int(number)
    except ValueError:
        abort(404)
    policy = request.form.get('widget_policy')
    if policy not in ('foo', 'bar'):
        abort(404)
    
    form = UpdateWidgetForm(widget_number=number, widget_policy=policy)
    

    请参阅文档中的How Forms get data

    如果您需要在一个页面中生成多个表单,每个表单都是唯一的,来自同一个表单对象,您需要使用 Form(prefix=..) 参数为每​​个表单指定一个唯一的前缀。

    【讨论】:

    • 感谢您的回复 Martijn。我今天花了很多时间研究这个(回复:将MultiDict 传递给表单),但我仍然有点卡住。我宁愿不要开始一个不必要的长 cmets 线程,所以你愿意接受关于这个的聊天或电子邮件线程吗?谢谢。
    • 我的理解有点远了(我想)。我最终不认为这(我想要完成的事情)对于 wtforms 是不可能的。 MultiDict 在具有多个具有相同键的值的情况下运行 - 此实例中的键对应于字段名称(因此在生成的 HTML 中的输入元素中的 name 参数)。我想要的是完全相反的 - 从同一个表单类生成多个字段,每个字段都有一个基于其他输入的唯一名称。
    • @JohnJensen: 然后使用prefix 参数到Form(): UpdateWidgetForm(prefix='unique_prefix') 来区分表单。
    • 这是有道理的,但这最终是一个带有多个字段的表单。我将编辑我的帖子以创建一个更加人为的示例,这可能会使我想要完成的工作更加清晰。
    • 您可以仍然使用多个表单对象来处理这些字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    • 2012-06-13
    相关资源
    最近更新 更多