Here's the code I've got, and this works. MyForm
is a form class, which defines only a RadioField
. The RadioField
has no default specified here, because we don't know what items it will contain yet. my_form
takes a list of items and creates a MyForm
with the items added to the RadioField
, and (crucially) picks the first item in the list to be the default.
from wtforms.fields.core import RadioField
from wtforms.validators import Required
from flask_wtf.form import Form
class MyForm(Form):
"""
User chooses an item.
"""
itemid = RadioField(validators=[Required()])
def my_form(items):
"""
Returns a MyForm object populated with appropriate items.
"""
form = MyForm()
form.itemid.choices = [(item.id, item.name)
for item in sorted(items, key=lambda i: i.order)]
if items and form.itemid.data == u'None':
# None ensures we don't overwrite submitted data
form.itemid.data = items[0].id
return form
The check and form.itemid.data == u'None'
just smells really bad. The reason for this is that without that check, we overwrite submitted data. I.e. when we use the form like this...
@APP.route('/page_one', methods=['GET', 'POST'])
def page_one():
form = my_form(dynamic_items())
if form.validate_on_submit():
itemid = form.itemid.data
return redirect(url_for('page_two', itemid=itemid))
else:
return render_template('page_one.html', form=form)
... if we don't have that smelly check, we set the form data so as to set the default, but in the case that form.validate_on_submit()
will pass because the user has submitted the form, by setting the default we've clobbered the actual data submitted by the user.
Of course, the obvious answer seems to be that my_form
should just set the default, so the smelly check should just become:
if items:
form.itemid.default = items[0].id
But that doesn't work, seemingly because form.itemid.data has no data, and that's what's actually used to construct the HTML.
So the question is: what is the right way to do this?