【问题标题】:Flask WTForms FieldList with BooleanFieldFlask WTForms FieldList 与 BooleanField
【发布时间】:2018-03-21 01:47:50
【问题描述】:

我想生成带有复选框的文件列表。我尝试使用 FieldList 但它没有按预期工作。我得到的不是带有指定文件名的复选框,而是带有以包含 FieldList 对象的变量命名的标签的复选框。有什么办法可以解决吗?

app.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)

模板/index.html

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

包:

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

【问题讨论】:

    标签: python python-3.x flask flask-wtforms


    【解决方案1】:

    根据文档,WTForms 的FieldList 不应与BooleanField 一起使用:

    注意:由于 HTML 发送值的方式存在限制,FieldList 不能包含 BooleanFieldSubmitField 实例。

    (即使 HTML 输出看起来有效。)也就是说,您并没有看到您希望看到的内容,因为 append_entry 的第一个参数接受表单输入的值,而不是其标签。

    相反,我建议动态创建表单类:

    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)
    

    注意:默认的 HTML 表示将在顶部具有“提交”按钮,因为库按照定义的顺序呈现字段。 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)
    

    【讨论】:

    • 谢谢。这正是我想要的。
    • 有人可以修改 jinja 代码以在 html 模板中显示名称为 filename_i 的复选框吗??
    • @RainerGlüge 嘿,你有没有想过这个 jinja 代码?
    • 这个解决方案很棒。我只是不知道如何在 Jinja 中单独渲染字段。一次渲染整个表单并不适合我的情况。有没有人想出如何做到这一点?即使我要将所有字段名的列表发送到模板,我仍然不确定如何正确使用它们。 {% for var_name in var_list %} {{ form.{{var_name}} }} {% endfor %} 我不认为你可以将双括号标签嵌套在一个标签内,但我想我会尝试回来报告。
    • 我传递了额外的信息来预先检查复选框:
    【解决方案2】:

    以防这对将来的任何人有所帮助。这就是我实现此解决方案的 jinja 部分的方式。

    我创建了一个变量名列表以发送到模板。 就我而言,我需要根据计数动态创建多个字段。 这些名称需要与您在构建表单时创建的名称相匹配,例如在为上述给定问题选择的解决方案中。

    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}'])
    

    在您的渲染模板语句中将此发送到模板 然后使用以下 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>
    

    这个解决方案的关键部分是这一行:

    {{ form[variable] }}
    

    我花了一段时间才弄清楚这是如何单独访问表单项的。

    希望这对将来的人有所帮助。

    干杯

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-16
      • 2018-08-10
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 2013-11-14
      • 2012-10-07
      • 1970-01-01
      相关资源
      最近更新 更多