Add input fields dynamically with wtforms
Sean Vieira's answer works great for StringFields
(previously TextField
), but things get a little trickier for dynamic SelectFields
. For anyone interesting in how to implement dynamic SelectFields
with wtforms
, see https://stackoverflow.com/a/57548509/7781935
WTForms has a meta-field called FormField
and another meta-field called FieldList
. These two combined together will get you what you want:
class AddressEntryForm(FlaskForm):
name = StringField()
class AddressesForm(FlaskForm):
"""A form for one or more addresses"""
addresses = FieldList(FormField(AddressEntryForm), min_entries=1)
To create entries in the AddressesForm, simply use a list of dictionaries:
user_addresses = [{"name": "First Address"},
{"name": "Second Address"}]
form = AddressesForm(addresses=user_addresses)
return render_template("edit.html", form=form)
Then, in your template, simply loop over the sub-forms:
{% from 'your_form_template.jinja' import forms %}
{% for address_entry_form in form.addresses %}
{{ address_entry_form.hidden_tag() }}
{# Flask-WTF needs `hidden_tag()` so CSRF works for each form #}
{{ forms.render_field(address_entry_form.name) }}
{% endfor %}
WTForms will automatically prefix the names and the IDs correctly, so when you post the data back you will be able to just get form.addresses.data
and get back a list of dictionaries with the updated data.