如何在WTForms中生成动态字段

18
我正在尝试使用 WTForms 生成一个具有动态字段的表单,根据这份文档:http://wtforms.simplecodes.com/docs/1.0.2/specific_problems.html#dynamic-form-composition 我有一个子表单类,允许用户从列表中选择要购买的物品:
class Item(Form):
    itmid = SelectField('Item ID')
    qty = IntegerField('Quantity')

class F(Form):
        pass

将会有多个购物项类别,因此我希望根据用户选择的类别生成动态选择字段:

fld = FieldList(FormField(Item))
fld.append_entry()

但是我得到了以下错误:

AttributeError: 'UnboundField' object has no attribute 'append_entry'

我是在使用WTForms的过程中出了问题,还是说无法用WTForms实现这个功能?


你能贴出更多关于你在使用fld的代码吗?最好是像文档中的示例那样,作为Form类的一个属性:http://wtforms.simplecodes.com/docs/1.0.2/fields.html#wtforms.fields.FieldList - aezell
6个回答

10

今晚我遇到了这个问题,最终解决了。希望这能帮助未来的人们。

RecipeForm.py

class RecipeForm(Form):
    category = SelectField('Category', choices=[], coerce=int)
    ...

视图.py

@mod.route('/recipes/create', methods=['POST'])
def validateRecipe():
    categories = [(c.id, c.name) for c in g.user.categories.order_by(Category.name).all()]
    form = RecipeForm(request.form)
    form.category.choices = categories
    ...

@mod.route('/recipes/create', methods=['GET'])
def createRecipe():
    categories = [(c.id, c.name) for c in g.user.categories.order_by(Category.name).all()]
    form = RecipeForm(request.form)
    form.category.choices = categories
    return render_template('recipes/createRecipe.html', form=form)

我也觉得这个帖子很有帮助。


7
class BaseForm(Form):
    @classmethod
    def append_field(cls, name, field):
        setattr(cls, name, field)
        return cls

from forms import TestForm
form = TestForm.append_field("do_you_want_fries_with_that",BooleanField('fries'))(obj=db_populate_object)

我在所有的表单中使用扩展类BaseForm,并在该类中添加了一个方便的append_field函数。
返回已附加字段的类,因为实例(表单字段)无法添加字段。

这会就地修改表单类。不要用于共享的类。考虑创建一个新的子类:return type(cls.__name__, (cls,), {name: field}) - Martijn Pieters

6

发表帖子时未编写完整的代码或测试代码,但可能会给您提供一些思路。此外,这可能只有在填写所需数据方面才有所帮助。

您需要填写SelectFieldchoices以便能够查看数据并能够选择它。您在哪里填写呢?最初的填充应该在表单定义中进行,但如果您喜欢动态填充,我建议您在创建此表单以向用户显示的地方进行修改。比如,您在进行一些form = YourForm()并将其传递给模板的视图中。

如何使用选项填充表单的选择字段?您必须拥有元组列表,然后像这样:

form.category_select.choices = [(key, categories[key]) for key in categories]
form.category_select.choices.insert(0, ("", "Some default value..."))

这里的categories必须是字典,格式如下:{1:'One', 2:'Two',...}。在定义表单时,如果为选项分配了某些数据,则它将从一开始就拥有该数据,在需要用户类别的位置,只需在视图中覆盖即可。希望这能给您一些想法,让您能够前进 :)

1
谢谢@ignas-b,但这只是填充选择字段的值,它并没有解决我遇到的错误。 - ChiliConSql
是的...当我发布答案时,我重新阅读了问题和答案,并添加了“也许这只能帮助填充所需的数据。”... :) 哦,好吧 :) - Ignas Butėnas

1
你是否尝试在表单实例上调用append_entry(),而不是在FieldList定义上进行调用?
class F(Form)
  fld = FieldList(SelectField(Item))

form = F()
form.fld.append_entry()

1
这是我让它正常工作的方法。
class MyForm(FlaskForm):
    mylist = SelectField('Select Field', choices=[])

@app.route("/test", methods=['GET', 'POST']
def testview():
    form = MyForm()
    form.mylist.choices = [(str(i), i) for i in range(9)]

奇怪的是,如果我使用coerce=int,整个东西就停止工作了。我自己是一个flask的初学者,所以我不太确定为什么coerce=int会导致问题。

-1

WTForms文档class wtforms.fields.SelectField

动态选择值的选择字段:

class UserDetails(Form):
    group_id = SelectField(u'Group', coerce=int)

def edit_user(request, id):
    user = User.query.get(id)
    form = UserDetails(request.POST, obj=user)
    form.group_id.choices = [(g.id, g.name) for g in Group.query.order_by('name')]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接