Solution
{% for field in form %}
{{ field.label }} {{ field() }}
{% endfor %}
from flask import Flask, request, render_template
from wtforms import Form, TextField
from wtforms.validators import InputRequired
from wtforms_dynamic_fields import WTFormsDynamicFields
from werkzeug.datastructures import ImmutableMultiDict
app = Flask(__name__)
class PersonalFile(Form):
""" A personal file form. """
first_name = TextField('First name', validators=[InputRequired()])
last_name = TextField('Last name', validators=[InputRequired()])
class Dict:
'''Wrapper klass because iteritems no longer available in Python3.7 dict'''
def __init__(self, mapping):
self.mapping = ImmutableMultiDict(mapping)
def iteritems(self):
return self.mapping.items()
def __getattr__(self, attr):
return getattr(self.mapping, attr)
def __iter__(self):
return dict.__iter__(self.mapping)
@app.route('/', methods=['GET', 'POST'])
def index():
dynamic = WTFormsDynamicFields()
dynamic.add_field('email', 'Email address', TextField)
dynamic.add_validator('email', InputRequired, message='This field is required')
dynamic.add_field('subject', 'Subject', TextField)
post = request.form.copy() # making a mutable dict copy
# add email in post mapping to declare
# that we are going to want this field in the form
post.add('email', '')
post = Dict(post) # Wrapping the mutable dict as immutable
# augumenting form with email field.
# Note that if we want to show the subject field,
# we must add the 'subject' key in the post mapping.
form = dynamic.process(PersonalFile, post)
if request.method == "POST":
return request.form
if request.method == 'GET':
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug=True)