Add input fields dynamically with wtforms
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.
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