Add fields dynamically to WTForms form

flask, flask-wtforms, python, wtforms

Solution

Use `setattr` to add new fields as attributes of the form class. This will cause WTForms to set up the field correctly instead of keeping the unbound field.

# form class with static fields
class MyForm(FlaskForm):
    name = StringField('static field')

record = {'field1': 'label1', 'field2': 'label2'}

# add dynamic fields
for key, value in record.items():
    setattr(MyForm, key, StringField(value))

In the template you can iterate over the fields using the `attr` filter.

{% for key, value in record.items() %}:
    {{ form|attr(key)() }}
{% endfor %}

Problem

I want to define a form class with fields based on a dict of `name: label`. I tried the following, which nearly worked. However, rendering the fields in a template gave `AttributeError: 'UnboundField' object has no attribute '__call__'`. How can I dynamically add fields to a form? ``` def build_form(name, record): class ContactForm(FlaskForm): name = StringField(name) fieldlist = {} for key, value in record.items(): fieldlist[key] = StringField(key) @app.route('/', methods=['GET', 'POST']) def showform(): form = ContactForm(request.form) if request.method == 'POST': return 'form processed' return render_template('cardcompare.tpl', record=record, form=form) ``` ``` <form method=post> {{ form.name() }} {% for key, value in record.items() %} {{ form.fieldlist[key]() }} {% endfor %} <input type=submit value=Register> </form> ```

Original source

Related problems