我正在创建一个基本上基于表单的Flask应用程序,所以我使用的是WTForms和Flask-wtf。
我目前正在重构我的代码,所以我的整个表单使用WTForms,并且我无法使用WTForms实现其中一个表单中非常动态的部分。我不知道怎么做,我最初的想法没有用,我找不到涉及我的问题的参考或教程,所以这就是我寻求帮助的原因。
因此,相关表单允许用户提交包含以下内容的对象:
你可以猜到我的列表有问题。代码的工作方式,我使用wtforms获取标签和描述,并使用配置常量生成属性列表(在整个代码中使用,因此如果我想添加新属性,我只有一个地方可以编辑)和javascript中的动态菜单创建(这里是谓词)字段,然后我可以在视图函数中使用flask.request.form对象。谓词的所有隐藏字段都具有相同的名称属性,对象的所有隐藏字段都具有相同的名称属性。
以下是表单视图的外观,初始化为一些属性:
http://i.imgur.com/bfMG95s.png
在“Propriétés”标签下,您有一个下拉列表来选择谓词,第二个字段会根据所选谓词显示或隐藏(可以是下拉列表或文本字段),只有当您点击“ Ajouterpropriété“(”添加属性“)在下面的选项卡中添加了一个新行,并生成了字段。
我不想在这方面改变任何东西,因为它非常好用,使形式非常直观,基本上就是我希望它来自用户端。
这就是我的自定义表单现在的样子(它不起作用,无论我使用表单提交的字段数量,属性都保持为空):
class PropertyForm(Form):
property_predicate = HiddenField(
validators=[AnyOf(values=app.config["PROPERTY_LIST"].keys())]
)
property_object = HiddenField(
validators=[DataRequired()]
)
class CategoryForm(Form):
"""
Custom form class for creating a category with the absolute minimal
attributes (label and description)
"""
label = StringField(
"Nom de la categorie (obligatoire)",
validators=[DataRequired()]
)
description = TextAreaField(
"Description de la categorie (obligatoire)",
validators=[DataRequired()]
)
properties = FieldList(FormField(PropertyForm),validators=[Optional()])
以下是我想在我的views.py代码(我目前正在重构)中做的事情:
def cat_editor():
cat_form = CategoryForm()
if request.method == "GET":
# Do GET stuff and display the form
return render_template("cateditor.html", form=cat_form, varlist=template_var_list)
else if request.method == "POST":
if cat_form.validate_on_submit():
# Get values from form
category_label = cat_form.label.data
category_description = cat_form.description.data
category_properties = cat_form.properties.data
# Do POST stuff and compute things
return redirect(url_for("index"))
else:
# form didn't validate so we return the form so the template can display the errors
return render_template("cateditor.html", form=cat_form,
template_var_list = template_var_list)
基本结构运作完美,只是该死的动态列表我无法正常工作。
从WTForms CategoryForm实例获取标签和描述工作正常,但属性始终返回空列表。理想情况下,我希望能够在调用cat_form.properties.data时获得表单[(predicate1,property1),(predicate2,object2)......]的列表(这就是为什么我有一个FormFields的FieldList有两个每个中都有HiddenField,但只要它使用WTForms,我就可以从两个列表中构建这样的列表。任何的想法?非常感谢:)
答案 0 :(得分:2)
我通过使用FieldList对象和append_entry()来了解问题是什么,以便在我创建预填充属性列表时查看Flask-wtf生成的HTML代码。
我的Javascript生成了具有相同名称的隐藏字段,据我所知,WTForms能够聚合具有相同名称的字段来创建列表。问题是,那些类似命名的字段是嵌套在FieldList对象名称属性中的FormField本身的一部分。
为了使WTForms Form对象能够从另一个隐藏字段中识别出一组隐藏字段,当您将FormFields嵌套在FieldList中时,它会在FormFields字段名称前加上" FieldList_name-index - "。这意味着WTForms期待的是像
<input type="hidden", name="properties-0-property_predicate" value=...>
<input type="hidden", name="properties-0-property_object" value=...>
<input type="hidden", name="properties-1-property_predicate" value=...>
<input type="hidden", name="properties-1-property_object" value=...>
<input type="hidden", name="properties-2-property_predicate" value=...>
<input type="hidden", name="properties-2-property_object" value=...>
我修改了我的javascript,因此它会生成相应的名称。现在,当我调用cat_form.properties.data时,我有一些看起来像:
[{"property_predicate": "comment", "property_object":"bleh"},
{"property_predicate": "comment", "property_object": "bleh2"}]
这正是我所需要的。由于某种原因,表单没有验证,但至少我知道如何使WTForms提取数据我的javascript生成的隐藏字段,这就是问题所在。
编辑:进行表单验证是因为您必须将csrf的CSRF隐藏输入插入到使用FormField生成的每个子表单中。
答案 1 :(得分:0)
使用jQuery表示表单中更具动态性的元素/行为。请注意,表单字段具有隐藏属性(或方法,具体取决于您是否使用引导程序),允许您呈现可能需要的所有内容,但仅在必要时显示字段,否则将隐藏它们。动态添加字段有点困难,但并非真的不可能。与属性关联的字段数是否有限制?如果是的话,我只是渲染最大字段数(只要它是合理的,最多5个似乎没问题,当你得到两位数作为用户可以添加的最大属性数,渲染一堆字段''永远不会使用变得不优雅。)
Here's一个好地方,看看它是如何运作的。当然,您还有另一个问题,即选择何时隐藏或显示相关字段,但也可以使用jQuery的.change()事件通过javascript / jQuery脚本处理。像这样:
$("#dropdown").change(function () {
var chosen_val = $(this).val();
if (chosen_val == 'banana'){$('#property1').show();} else {$('#property1').hide();}
});
此代码可能不工作,并且肯定缺乏正确的逻辑,但应该让您了解如何使用jQuery解决此问题。请注意,'property1'字段始终存在,等待用户选择正确的下拉值时显示。