使用字典插入WTForm字段。 jinja2.exceptions.UndefinedError:'wtforms.fields.core.UnboundField对象'没有属性'标签'

时间:2019-04-26 16:50:36

标签: python html flask jinja2 wtforms

我正在尝试使用字典中的表单字段填充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循环遍历字典元素以插入所有字段,而无需一个个地键入内容。

2 个答案:

答案 0 :(得分:1)

问题

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

解决方案

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

多余的表单字段通过library(plm) data(Cigar) cigar_data = log(Cigar) cigar_data$state = Cigar$state cigar_data$year = Cigar$year cigar_data$lsales = lag(cigar_data$sales,1) library(dummies) cigar_data = cbind(cigar_data,dummy(cigar_data$year)) cigar_data = pdata.frame(cigar_data,index = c("state","year")) q3_ols = plm(sales ~ lag(sales,1) + price + ndi + pimin, data = cigar_data, effect = "time", model = "within") q3_gmm = pgmm(sales ~ lag(sales,1) + price + ndi + pimin| price + ndi + pimin + cigar_data63, data = cigar_data, effect = "individual", model = "twosteps") summary(q3_ols) summary(q3_gmm) 参数作为lambda函数传递,因此我们可以将多余字段的创建延迟到创建field_factory字段之后(尽管任何返回的可调用项一个字典将起作用)。这是必需的,因为WTForms会根据创建顺序而不是根据name函数内的items字典中提供的顺序对字段进行排序。

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

在python 3.7.1上测试。

make_form()

输出

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())


答案 1 :(得分:0)

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

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