微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

创建自定义 Flask WTForms 小部件

如何解决创建自定义 Flask WTForms 小部件

我有一个自定义 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)

我尝试将 FieldListFormField 一起使用,该 BooleanField 包含带有 BooleanField自定义表单,并设法使样式正确,但表单验证不起作用。进一步研究后,FieldListWTForm 不兼容。

我的下一步是使用 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]}')

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。