I'm not quite sure how approach this matter. I hope i get there.
For example I have a table full of addresses on a page. The count of these are dynamic (could be 5 or 10 or any other count). And I want the possibility to edit them on one page.
My approach was to create a Form with wtforms to edit one address and to multiply
it in a jinja2 for loop
and append to the html propertys name
and id
the
loop.index0
from the itereation, so i can extract each row of data manually
and put it back in my form, when I want to evaluate it.
So the Form for this example would be:
class AdressForm(Form):
name = TextField()
so now my template aproach looks like the following (break down to one input field):
{% for address in addresses %}
{{ forms.render_field(addressform.name, id = "name_" ~ loop.index0,
name = "name_" ~ loop.index0, value = address.name) }}
{% endfor %}
(forms.render_field is just a macro to specify the right classes to the field function of wtforms. like they use in many tutorials)
So this is not working, since you can't pass the name
parameter manually to the field function, since wtforms create the name
html-paramter from the variblename of the intial Form.
So is there a way to add a prefix or postfix to the name of a form I want to render. Or is this a XY-Problem and my approach is totaly wrong.
or have I do it all plain by myself (I really try to avoid this)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With