简体   繁体   English

带有 BooleanField 的 Flask WTForms FieldList

[英]Flask WTForms FieldList with BooleanField

I'd like to generate list of files with checkboxes.我想生成带有复选框的文件列表。 I've tried to use FieldList but it doesn't work as I expected.我尝试使用 FieldList 但它没有按我预期的那样工作。 Instead of checkbox with assigned filename I'm getting checkbox with label named after the variable containing FieldList object.我得到的不是带有指定文件名的复选框,而是带有以包含 FieldList 对象的变量命名的标签的复选框。 Is there any way to fix it?有什么办法可以解决吗?

app.py:应用程序.py:

from flask import Flask, render_template
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import BooleanField, FieldList, SubmitField

app = Flask(__name__)
app.config['SECRET_KEY'] = 'development'
Bootstrap(app)

filenames = ['1.jpg', '2.jpg', '3.jpg', '4.jpg']


class FileListForm(FlaskForm):
    filename = FieldList(BooleanField(), 'Files')
    submit = SubmitField('Submit')


@app.route('/')
def listfiles():
    form = FileListForm()
    for filename in filenames:
        form.filename.append_entry(filename)
    return render_template('index.html',
                           form=form)


if __name__ == '__main__':
    app.run(debug=True, port=5001)

templates/index.html模板/index.html

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

packages:包:

click==6.7
dominate==2.3.1
Flask==0.12.2
Flask-Bootstrap==3.3.7.1
Flask-WTF==0.14.2
itsdangerous==0.24
Jinja2==2.9.6
MarkupSafe==1.0
visitor==0.1.3
Werkzeug==0.12.2
WTForms==2.1

According to the documentation, WTForms' FieldList shouldn't be used with BooleanField :根据文档,WTForms 的FieldList不应与BooleanField一起使用:

Note: Due to a limitation in how HTML sends values, FieldList cannot enclose BooleanField or SubmitField instances.注意:由于 HTML 发送值方式的限制, FieldList不能包含BooleanFieldSubmitField实例。

(Even though the HTML output appears valid.) That said, you're not seeing what you're expecting to see because append_entry 's first parameter accepts the form input's value, not its label. (即使 HTML 输出看起来有效。)也就是说,您没有看到您期望看到的内容,因为append_entry的第一个参数接受表单输入的值,而不是其标签。

Instead, I'd recommend creating the form class dynamically:相反,我建议动态创建表单类:

filenames = ['1.jpg', '2.jpg', '3.jpg', '4.jpg']

class FileListFormBase(FlaskForm):
    submit = SubmitField('Submit')

def file_list_form_builder(filenames):
    class FileListForm(FileListFormBase):
        pass

    for (i, filename) in enumerate(filenames):
        setattr(FileListForm, 'filename_%d' % i, BooleanField(label=filename))

    return FileListForm()

@app.route('/')
def listfiles():
    form = file_list_form_builder(filenames)
    return render_template('index.html', form=form)

Note: The default HTML representation will have the "Submit" button at the top, since the library renders fields in the order they're defined.注意:默认的 HTML 表示将在顶部有“提交”按钮,因为库按照定义的顺序呈现字段。 WTForms doesn't natively support ordering, so this may be a better solution for you even though it's less elegant: WTForms 本身不支持排序,所以这对你来说可能是一个更好的解决方案,即使它不太优雅:

filenames = ['1.jpg', '2.jpg', '3.jpg', '4.jpg']

def file_list_form_builder(filenames):
    class FileListForm(FlaskForm):
        pass

    for (i, filename) in enumerate(filenames):
        setattr(FileListForm, 'filename_%d' % i, BooleanField(label=filename))

    setattr(FileListForm, 'submit', SubmitField('Submit'))
    return FileListForm()

@app.route('/')
def listfiles():
    form = file_list_form_builder(filenames)
    return render_template('index.html', form=form)

In case this helps anyone in the future.如果这对将来的任何人有帮助。 This is how I implemented the jinja part of this solution.这就是我实现此解决方案的 jinja 部分的方式。

I created a list of variable names to send to the template.我创建了一个要发送到模板的变量名称列表。 In my case I needed to dynamically create several fields based on a count.就我而言,我需要根据计数动态创建多个字段。 These names need to match the names you created while building the form, such as in the selected solution for this given problem above.这些名称需要与您在构建表单时创建的名称相匹配,例如在上面针对此给定问题的选定解决方案中。

variable_names_list = []
for i in range(1, count+1):
    variable_names_list.append([f'var1_name_{i}',f'var2_name_{i}',f'var3_name_{i}',f'var4_name_{i}'])

Send this to template in your render template statement And then use the following jinja to in order to show your form items将此发送到您的渲染模板语句中的模板然后使用以下 jinja 来显示您的表单项

                    <div class="row">
                        <table class="table table-bordered">
                            <tbody>
                                {{ form.csrf_token }}
                                {% for variable_names in variable_names_list %}
                                <tr>
                                    {% for variable in variable_names %} 
                                        <td>
                                            {{ form[variable] }}
                                        </td>
                                    {% endfor %}
                                </tr>

                                {% endfor %}
                            </tbody>

                        </table>
                    </div>

The key part of this solution is this line:此解决方案的关键部分是这一行:

{{ form[variable] }}

It took me a while to figure out this is how one can access the form items individually.我花了一段时间才弄清楚这是如何单独访问表单项的。

Hope this helps someone in the future.希望这对未来的人有所帮助。

Cheers干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM