【问题标题】:Using a dictionary to insert WTForm fields. jinja2.exceptions.UndefinedError: 'wtforms.fields.core.UnboundField object' has no attribute 'label'使用字典插入 WTForm 字段。 jinja2.exceptions.UndefinedError: 'wtforms.fields.core.UnboundField object' 没有属性 'label'
【发布时间】:2019-09-16 05:21:01
【问题描述】:

我正在尝试使用字典中的表单字段填充 jinja2 中的表单。

#forms.py
class MyForm(FlaskForm):
    name = StringField('New Name', validators=[DataRequired()])

    fields = {}
    fields['Field1'] = StringField('Field 1', validators=[DataRequired()])
    fields['Field2'] = StringField('Field 2', validators=[DataRequired()])

#routes.py
@app.route('/test', methods=['GET', 'POST'])
def test():
    form = MyForm()
    return render_template('_test.html', form=form)

我的python代码和上面的代码类似。如果我尝试在 jinja2 中插入 name 字段,它可以正常工作。

{{ form.name.label(class="form-control-label form-control-sm") }}

但是,我不知道如何对 fields 字典中的字段执行相同操作。如果我使用以下内容,它会给我一个错误。(jinja2.exceptions.UndefinedError: 'wtforms.fields.core.UnboundField object' has no attribute 'label')

{{ form.fields['Field1'].label(class="form-control-label form-control-sm") }}

是否可以按照我尝试使用的方式使用字典,或者如果我有大量字段,是否有替代方法。我使用字典的目标是使用 jinja2 循环遍历字典元素以插入所有字段而无需一一键入。

【问题讨论】:

  • 您不能在表单之外使用字段。你为什么这样做?
  • 我没有在表单之外使用它们。你为什么说我在表格之外使用它?我不确定你的意思是什么?
  • 那我看不懂你的代码。表格在哪里定义,字典从哪里来?请显示完整视图。
  • 编辑了代码。这有帮助吗?

标签: python html flask jinja2 wtforms


【解决方案1】:

问题

WTForms 不支持在类级别字典属性中定义字段。 Form 基类使用 FormMeta(来自同一文件)作为元类来识别类定义中未绑定的 WTForm 字段并将它们绑定到当前 Form,这只会发现类级别的属性。

解决方案

下面是使用表单工厂函数的最小工作示例。

额外的表单字段通过 field_factory 参数作为 lambda 函数传入,这样我们就可以延迟创建额外字段,直到创建 name 字段之后(尽管任何返回 dict 的调用都可以)。这是必需的,因为 WTForms 按创建顺序而不是按在 make_form() 函数内的 items dict 中提供的顺序对字段进行排序。

然后您可以通过迭代表单而不是指定手动顺序来呈现它们。

在 python 3.7.1 上测试。

from flask import Flask
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired

app = Flask(__name__)
app.config['SECRET_KEY'] = "secret"


def make_form(field_factory, name="MyForm"):
    items = dict(name=StringField('New Name', validators=[DataRequired()]),
                 **field_factory())
    my_form = type(name, (FlaskForm,), items)
    return my_form


if __name__ == "__main__":
    with app.test_request_context("/"):
        my_form = make_form(field_factory=lambda: dict(
            Field1=StringField('Field 1', validators=[DataRequired()]),
            Field2=StringField('Field 2', validators=[DataRequired()])
        ))

        form = my_form()
        for field in form:
            print(field())


输出

<input id="name" name="name" required type="text" value="">
<input id="Field1" name="Field1" required type="text" value="">
<input id="Field2" name="Field2" required type="text" value="">
<input id="csrf_token" name="csrf_token" type="hidden" value="IjY5ZWMyNWYxYzg3MzU2MTM1MGMyMTI0OTNiOGY1ZTk4OWFkZWU2Y2Qi.XMNLww.uvari0GZi4weboIecdtv9Vl8Jvg">

【讨论】:

  • 这看起来是解决问题的好方法。我最终使用exec 根据存储在字典中的字段参数来定义字段。然后我使用@DanielRoseman 提到的方法对它们进行迭代,如WTForms docs 所示。
【解决方案2】:

你不能这样做。字段需要直接在表单本身中定义。

但你不需要。如果你只想遍历字段,你可以这样做,如the WTForms docs所示。

【讨论】:

  • 好的。所以这意味着我不能在 forms.py 中使用循环来创建遍历预定义键的字段并将它们放入字典中以在 jinja2 中使用。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
  • 1970-01-01
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多