[英]WTForm: FieldList with SelectField, how do I render?
I have this order form that allows my users to create an order.我有这个订单表,允许我的用户创建订单。 An order consists of multiple tuples of
(producetype, quantity)
.一个订单由多个
(producetype, quantity)
元组组成。 Producetype should be rendered in a <select>
form while quantity can just be an input. Producetype 应该以
<select>
形式呈现,而数量可以只是一个输入。 The choices of producetype should be dynamically added because that could change.应该动态添加生产类型的选择,因为这可能会改变。 Currently, I've written this in bare html
目前,我已经用裸 html 写了这个
I would like to use WTForm for this because WTForm really simplifies my code.我想为此使用 WTForm,因为 WTForm 确实简化了我的代码。 However, I am unable to do so:
但是,我无法这样做:
Code:代码:
class OrderEntryForm(Form):
quantity = IntegerField('Quantity',
[validators.Required(), validators.NumberRange(min=1)])
# we will be dynamically adding choices
producetype = SelectField('Produce',
[validators.Required()],
choices=[])
class OrderForm(Form):
name = TextField('Crop', [validators.Length(min=3, max=60)])
due_date = DateField('Due Date', [validators.required()])
order_entries = FieldList(FormField(OrderEntryForm))
I have the following questions:我有以下问题:
order_entries
field of the OrderForm?order_entries
字段?order = { name:hello, due_date:2014-06-18, order_entries:[ {producetype_id: 1, quantity: 2}, {producetype_id: 3, quantity: 4}] }
, how can populate my OrderForm
with the right OrderEntryForm
values?order = { name:hello, due_date:2014-06-18, order_entries:[ {producetype_id: 1, quantity: 2}, {producetype_id: 3, quantity: 4}] }
,如何填充我的具有正确OrderEntryForm
值的OrderForm
?How can I dynamically add choices to the order_entries field of the OrderForm
如何将选项动态添加到 OrderForm 的 order_entries 字段
This depends on what you mean这取决于你的意思
If you mean you want to add lines items to the form after render.如果您的意思是要在渲染后向表单添加行项目。 You have to use DOM manipulation to add these on the client side.
您必须使用 DOM 操作在客户端添加这些。 WTForms has a naming convention for addressing indices on form fields.
WTForms有一个命名约定来处理表单字段上的索引。 Its just
name="<form-field)name>-<index>"
.它只是
name="<form-field)name>-<index>"
。 If you add a name using javascript that follows this convention WTForms will know how to handle it on the backend.如果您使用遵循此约定的 javascript 添加名称, WTForms将知道如何在后端处理它。
If you mean you want to have a dynamic choice list then you can just iterate over the FieldList
in the form after its instantiated.如果你的意思是你想要一个动态的选择列表,那么你可以在实例化后迭代表单中的
FieldList
。 You can assign choices
any iterable of 2-tuples.您可以分配
choices
任何可迭代的 2 元组。 In the example below I am assigning them directly but they could just as easily have been retrieved from storage.在下面的示例中,我直接分配了它们,但它们也可以很容易地从存储中检索。
order_form = OrderForm()
for sub_form in order_form.order_entries:
sub_form.producetype.choices = [('2', 'apples'), ('2', 'oranges')]
how can populate my OrderForm with the right OrderEntryForm values?
如何使用正确的 OrderEntryForm 值填充我的 OrderForm?
You can just bind objects directly to the form using the obj
keyword argument.您可以使用
obj
关键字参数将对象直接绑定到表单。 WTForms is smart enough to dynamically build the form from the object's attributes. WTForms足够智能,可以根据对象的属性动态构建表单。
from wtforms import Form, IntegerField, SelectField, TextField, FieldList, FormField
from wtforms import validators
from collections import namedtuple
OrderEntry = namedtuple('OrderEntry', ['quantity', 'producetype'])
Order = namedtuple('Order', ['name', 'order_entries'])
class OrderEntryForm(Form):
quantity = IntegerField('Quantity',
[validators.Required(), validators.NumberRange(min=1)])
# we will be dynamically adding choices
producetype = SelectField('Produce',
[validators.Required()],
choices=[
(1, 'carrots'),
(2, 'turnips'),
])
class OrderForm(Form):
name = TextField('Crop', [validators.Length(min=3, max=60)])
order_entries = FieldList(FormField(OrderEntryForm))
# Test Print of just the OrderEntryForm
o_form = OrderEntryForm()
print o_form.producetype()
# Create a test order
order_entry_1 = OrderEntry(4, 1)
order_entry_2 = OrderEntry(2, 2)
order = Order('My First Order', [order_entry_1, order_entry_2])
order_form = OrderForm(obj=order)
print order_form.name
print order_form.order_entries
The above example creates a sample Order
and supplies it to the obj
keyword.上面的示例创建了一个示例
Order
并将其提供给obj
关键字。 On render this will generate the following(unstyled):在渲染时,这将生成以下内容(无样式):
For anyone else stumped by SelectField
s + FieldList
s, this is how I implemented a FieldList
with SelectField
s (inspired by nsfyn55's answer ).对于其他被
SelectField
s + FieldList
s 难倒的人,这就是我使用SelectField
s 实现FieldList
的方式(受nsfyn55 的回答启发)。 This approach dynamically renders an arbitrary number of SelectFields to the /home
route based on JSON data.这种方法基于 JSON 数据将任意数量的 SelectField 动态呈现到
/home
路由。
The route (routes.py):路线(routes.py):
@app.route('/home', methods=['POST', 'GET'])
def home():
custom_metadata = data
select_metadata_form_list = SelectFormList()
select_metadata_form_list.select_entries = get_select_entries()
context = {
"select_metadata_form_list": select_metadata_form_list,
}
return render_template('home.html', **context)
The forms (forms.py):表格(forms.py):
class SelectForm(FlaskForm):
select = SelectField("Placeholder", choices=[])
class SelectFormList(FlaskForm):
select_entries = FieldList(FormField(SelectForm))
The template ( home.html
):模板(
home.html
):
{% for select_form in select_metadata_form_list.select_entries %}
{{select_form.select.label}}: {{ select_form.select}}
{% endfor %}
Helper methods (app.py):辅助方法(app.py):
def get_select_entries():
"""
Converts custom metadata to a forms.SelectForm(), which can then be
used by SelectFormlist() to dynamically render select items.
:return: <forms.SelectForm object>
"""
select_data = get_select_data_from_custom_metadata()
select_data_labeled = get_labled_select_data(select_data=select_data)
all_select_items = []
for select_dict in select_data_labeled:
for k, v in select_dict.items():
select_id = uuid.uuid1() # allows for multiple selects
select_entry = SelectForm()
select_entry.select.label = k
select_entry.id = select_id
select_entry.select.choices = v
all_select_items.append(select_entry)
return all_select_items
def get_select_data_from_custom_metadata():
"""
[
{"Seniority": ["Intern", "Associate", "Senior"]}
]
:return: List of dictionaries containing key and list of select values
"""
type = "select"
select_data = []
custom_metadata = get_custom_metadata()
for field in custom_metadata["fields"]:
if field["type"] == type:
select_data.append({field["key"]: field["data_list"]})
return select_data
The 'data' (custom_metadata.json): “数据” (custom_metadata.json):
{
"fields": [
{
"type": "text",
"key": "Position"
},
{
"type": "select",
"key": "Seniority",
"data_list": ["Intern", "Associate", "Senior", "Executive"]
},
{
"type": "select",
"key": "Company",
"data_list": ["Ford", "Chevy", "Toyota"]
},
{
"type": "select",
"key": "Team",
"data_list": ["Bucks", "Raptors", "Thunder"]
}
]
}
The result :结果:
Add a SubmitField
to your to OrderForm
:将
SubmitField
添加到您的 to OrderForm
:
submit_something = SubmitField((u'Add something'))
and then call it from your view, and use the append_entry
method of FieldList
:然后从您的视图调用它,并使用
append_entry
的方法FieldList
:
if form.submit_something.data:
form.order_entries.append_entry()
return render_template('yourtemplate.html', form=form)
Hope that helps !希望有帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.