Python WTForms:如何动态设置FormFields中FieldList的SelectField选项?

2 投票
1 回答
1480 浏览
提问于 2025-04-18 03:56

我现在正在尝试使用 WTFormsFieldListFormField 来让用户添加自定义的地点和相应的保险金额。

这个表单会给用户一些标准的输入选项,然后初始化一个包含地点选择和保险金额输入的字段组(FormField)。

通过JavaScript,用户可以根据需要添加或删除额外的地点和保险金额字段,以确保文档信息的准确性。

问题: 目前我在处理表单时,使用了一种变通的方法,通过在GET请求中传递一个模板变量来设置地点选项,并手动创建自己的表单字段。但这样并没有更新实际的WTForms地点字段选项,所以当我提交表单时,地点字段会抛出一个异常(‘不是有效的选择’)。

我该如何在实例化 MyForm 时动态地向 LocationFormlocation 字段添加地点选项呢?

我的代码大致是这样的:

注意:我省略了在GET请求中创建地点模板变量的代码,因为那不是我想要的设计。我希望能更符合WTForms的设计理念。

class LocationForm(Form):
    location = SelectField('Location', [], choices=[])
    coverage = FloatField('Coverage', [])

class MyForm(BaseForm):
    # other fields omitted for brevity
    location_coverage = FieldList(FormField(LocationForm), [], min_entries=1)

class AddDocument(BaseHandler):

    def get(self):
        params = {
           "cid": cid
        }
        return self.render_template("form.html", **params)

    def post(self):
        cid = self.request.get('cid')
        if not self.form.validate():
            return self.get()
        company_key = ndb.Key('Company', cid)
        doc = Document(parent=company_key)
        self.form.populate_obj(doc)
        doc.put()
        params = { 
            "cid": 
        }
        return self.redirect_to('view_company', **params)

    @webapp2.cached_property
    def form(self):
        f = MyForm(self)

        # HERE is where I would normally do something like:
        # company = ndb.Key('Company', int(self.request.get('cid')))
        # locations = ndb.Location.query(ancestor=company).fetch() 
        # f.field_name.choices = [(loc.key, loc.name) for loc in locations]
        # but this doesn't work with Select Fields enclosed in 
        # FormFields and FieldLists.

        return f

编辑:

我找到了一个解决方案,但这并不是我想要的答案。在我的情况下,我只是把 LocationForm.location 的表单字段从 SelectField 改成了 StringField。这样做绕过了选择字段选项的验证,允许表单提交。但这并不是理想的做法,因为这不是我想要的设计。如果有人能指导我在这种情况下更正确地使用WTForms,我将非常感激。

1 个回答

2

如果你的BaseForm类在创建的时候就从提交的数据中填充表单,那么你应该能在通常添加选项到SelectField的地方看到嵌套的表单也被填充了。

所以像这样:

for entry in f.location_coverage.entries:
    entry.location.choices = [(loc.key, loc.name) for loc in locations]

应该会把选项填充到每个子表单的选择框里。

撰写回答