FieldList 中动态调整的表单

Dynamically adjusted forms inside FieldList

我正在使用 Flask 和 Flask-WTF,我需要创建一个包含多个具有相似结构的块(子表单)的表单(比如一个包含一个 SelectField 和一个 TextAreaField 的子表单) ).作为 docs suggest, I can use FormField together with FieldList to achieve this goal. However, I need to tweak my SelectField's dynamically (changing their choices at runtime according to values in the database). The docs now suggest

Note that the choices keyword is only evaluated once, so if you want to make a dynamic drop-down list, you’ll want to assign the choices list to the field after instantiation.

可以找到这种方法的示例 。然而,FormField 正在接受 form_class,而不是一个实例(至少,根据文档),所以这两个配方似乎不能很好地结合在一起。

还有其他想法吗?

好的,这比我想象的要容易。您必须创建那些带有空选项的子表单,创建它们的列表,然后调整列表项中的选项。

class UserForm(wtforms.Form):
# must inherit from wtforms.Form, not flask-WTForms'
# see 
    first_name = StringField('First Name', [validators.DataRequired()])
    last_name = StringField('Last Name', [validators.DataRequired()])
    accepted_policy = BooleanField('Accept Policy')
    experience = SelectField('Experience', coerce=int)

class UsersForm(Form):
    users = FieldList(FormField(UserForm), min_entries=2)

@app.route('/', methods=['GET', 'POST'])
def hello_world():

    form = UsersForm(users=[{}, {}, {}])
    form.users[0].experience.choices=[(1, 'One'), (2, 'Two')]
    form.users[1].experience.choices = [(1, 'Uno'), (2, 'Du')]
    form.users[2].experience.choices = [(0, 'Zero')]
    return render_template("hello.html", form=form)

这是一个模板:

{% macro render_field(field) %}
  <dt>{{ field.label }}
  <dd>{{ field(**kwargs)|safe }}
  {% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </dd>
{% endmacro %}

<form method=post>
  <dl>
      {{ form.hidden_tag()}}
      {%  for user_entry_form in form.users %}
          {{ user_entry_form.name }}
    {{ render_field(user_entry_form.first_name) }}
    {{ render_field(user_entry_form.last_name) }}
    {{ render_field(user_entry_form.experience) }}
      {%  endfor %}
  </dl>
  <p><input type=submit value=Go!>
</form>