问题描述
我有一个自定义 Flask WTForm
,我想在其中包含该表单的一部分,其中包含基于表中条目数创建的按钮类型输入列表,但在使用它们时遇到困难以我想要的方式显示并通过表单验证。我对这个字段外观的目标是让它显示为 Inline Button Group with a Checkbox type input。下面是我的路由方法的一个例子。
@bp.route('/new_channel',methods=['GET','POST'])
def new_channel():
# Pre-populate the NewChannelForm
newChannelForm = NewChannelForm()
newChannelForm.required_test_equipment.choices = [(equip.id,equip.name) for equip in TestEquipmentType.query.order_by('name')]
test_equipment_types = TestEquipmentType.query.all()
return render_template('new_channel.html',title='Add New Channel',form=newChannelForm,test_equipment_types=test_equipment_types)
我尝试将 FieldList
与 FormField
一起使用,该 BooleanField
包含带有 BooleanField
的自定义表单,并设法使样式正确,但表单验证不起作用。进一步研究后,FieldList
与 WTForm
不兼容。
我的下一步是使用 Flask MultiSelectField
示例 class MultiCheckBoxField(SelectMultipleField):
"""
A multiple-select,except displays a list of checkBoxes.
Iterating the field will produce subfields,allowing custom rendering of
the enclosed checkBox fields.
"""
widget = widgets.ListWidget(prefix_label=False)
option_widget = widgets.CheckBoxinput()
以及用于字段的自定义小部件和用于选项的自定义小部件。默认如下图所示:
InLineButtonGroupWidget
我的目标是修改它以制作一个名为 option_widget
的自定义小部件,它将使用样式作为内嵌按钮列表,例如我之前包含的图片。此外,我希望创建一个名为 CheckBoxButtonInput
的自定义 <div class="btn-group-toggle" role="group" data-toggle="buttons"></div>
来获取每个单独按钮的样式,我可以在其中将信息传递给字段。这就是我对两者的目标:
InLineButtonGroupWidget:
<label class="btn btn-outline-info" for="check-1">Calibrator
<input type="checkBox" id="check-1">
</label>
CheckBoxButtonInput:
@bp.route('/new_channel','POST'])
def new_channel():
class NewChannelForm(FlaskForm):
pass
test_equipment_types = TestEquipmentType.query.all()
for test_equipment_type in test_equipment_types:
# Create field(s) for each query result
setattr(NewChannelForm,f'checkBox_{test_equipment_type.name}',BooleanField(label=test_equipment_type.name,id=f'checkBox-{test_equipment_type.id}'))
newChannelForm = NewChannelForm()
if newChannelForm.validate_on_submit():
print('Form has been validated')
for test_equipment_type in test_equipment_types:
if newChannelForm.data[f'checkBox_{test_equipment_type.name}']:
channel.add_test_equipment_type(test_equipment_type)
return redirect(url_for('main.index'))
print(newChannelForm.errors.items())
return render_template('new_channel.html',units_dict=ENG_UNITS,test_equipment_types=test_equipment_types)
关于如何创建自定义小部件的文档有点超出我的理解并且没有最好地解释它,所以我正在寻找一些
编辑: 使用了 Andrew Clark 的建议,这是我的最终实现:
routes.py
<!-- Test Equipment Selection -->
<div class="row">
<legend>Test Equipment Selection:</legend>
<div class="col-md-12">
<div class="btn-group-toggle mb-3" role="group" data-toggle="buttons">
{% for test_equipment_type in test_equipment_types %}
<label class="btn btn-outline-info" for="checkBox-{{ test_equipment_type.id }}">
{{ test_equipment_type.name }}
{{ form['checkBox_{}'.format(test_equipment_type.name)] }}
</label>
{% endfor %}
</div>
</div>
</div>
new_channel.html
{{1}}
解决方法
我通常做这样的事情来处理表单构建:
def buildNewChannelForm():
class NewChannelForm(FlaskForm):
# put any non dynamic fields here
pass
test_equipment_types = TestEquipmentType.query.all()
for test_equipment_object in test_equipment_types:
# create field(s) for each query result
setattr(NewChannelForm,f'field_name_{test_equipment_object.id}',SelectField(label='label name',choices=[(equip.id,equip.name) for equip in TestEquipmentType.query.order_by('name')]))
return NewChannelForm()
编辑 1:
我不确定是否有更好的方法来做到这一点,但我通常会做这样的事情来处理数据提交
def buildNewChannelForm():
new_channel_form_variable_list = []
class NewChannelForm(FlaskForm):
# put any non dynamic fields here
pass
test_equipment_types = TestEquipmentType.query.all()
for test_equipment_object in test_equipment_types:
# create field(s) for each query result
setattr(NewChannelForm,equip.name) for equip in TestEquipmentType.query.order_by('name')]))
# append variable name
new_channel_form_variable_list.append(f'field_name_{test_equipment_object.id}')
return NewChannelForm(),new_channel_form_variable_list
然后您可以使用变量列表呈现表单,只需包含在您的 render_template 语句中
{% for variable_name in new_channel_form_variable_list %}
{{ form[variable_name] }}
{% endfor %}
然后在路由中提交表单,它只是一个字典。所以你可以做这样的事情
result_dictionary = form.data
# either loop through your variable list or handle each one individually
for variable_name in new_channel_form_variable_list:
print(f'variable name: {variable_name},value: {result_dictionary[variable_name]}')