我正在努力弄清楚如何完成与表中另一个元素相关联的唯一表单域实例。对于人为的示例,下面是以下代码:

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”上,如果输入了电话号码,则该电话号码为现在填充表中所有名称行。 “激活”复选框也是如此。我也尝试过生成表单实例列表并将该列表传递到模板中,但是它似乎并没有按我预期的那样工作。在这一点上,我的选择似乎是:


不要为此使用WTForms(请参阅下面的注释)
使用WTForms FieldList + FormField(我认为这不起作用,因为它们需要命名键与任意键,因此我会遇到完全相同的问题。)
以某种方式使用HiddenFields(甚至都没有想到这将如何工作)。


我知道我可以通过模板手动在表中创建<input type>元素,并根据w为它们分配不同的名称/ id,但这并不是很习惯,而且我必须编写代码我自己进行验证。

最佳答案

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

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=..)参数。

10-06 10:15
查看更多