dis*_*dng 8 python flask wtforms flask-wtforms
我有这个订单表格,允许我的用户创建订单.订单由多个元组组成(producetype, quantity).Producetype应该以<select>表单形式呈现,而数量只能是输入.应该动态添加producetype的选择,因为这可能会改变.目前,我用裸HTML编写了这个

我想使用WTForm,因为WTForm真的简化了我的代码.但是,我无法这样做:
码:
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))
Run Code Online (Sandbox Code Playgroud)
我有以下问题:
order_entriesOrderForm 的字段中?order = { name:hello, due_date:2014-06-18, order_entries:[ {producetype_id: 1, quantity: 2}, {producetype_id: 3, quantity: 4}] }怎么能用OrderForm正确的OrderEntryForm价值填充我?我的代码可以在这里找到:https://gist.github.com/vicngtor/f8c8f0519dbd6b3b6110
如何动态地将选择添加到OrderForm的order_entries字段中
这取决于你的意思
如果您的意思是要在渲染后将订单项添加到表单中。您必须使用DOM操作将它们添加到客户端。WTForms具有用于处理表单字段索引的命名约定。它只是name="<form-field)name>-<index>"。如果您使用遵循此约定的javascript添加名称,则WTForms将知道如何在后端处理它。
如果您想拥有一个动态选择列表,则可以FieldList在实例化窗体后在其上进行迭代。您可以分配choices任何可重复的2元组。在下面的示例中,我直接分配了它们,但是可以很容易地从存储中检索它们。
order_form = OrderForm()
for sub_form in order_form.order_entries:
sub_form.producetype.choices = [('2', 'apples'), ('2', 'oranges')]
Run Code Online (Sandbox Code Playgroud)
如何用正确的OrderEntryForm值填充我的OrderForm?
您可以使用obj关键字参数将对象直接绑定到表单。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
Run Code Online (Sandbox Code Playgroud)
上面的示例创建了一个示例Order,并将其提供给obj关键字。在渲染时,将生成以下(未样式化):

对于其他被SelectFields + FieldLists难倒的人,这就是我实现 a FieldListwith SelectFields 的方式(受nsfyn55 的回答启发)。这种方法/home根据 JSON 数据动态地将任意数量的 SelectField 呈现给路由。
路线(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)
Run Code Online (Sandbox Code Playgroud)
表格(forms.py):
class SelectForm(FlaskForm):
select = SelectField("Placeholder", choices=[])
class SelectFormList(FlaskForm):
select_entries = FieldList(FormField(SelectForm))
Run Code Online (Sandbox Code Playgroud)
模板(home.html):
{% for select_form in select_metadata_form_list.select_entries %}
{{select_form.select.label}}: {{ select_form.select}}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
辅助方法(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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
“数据”(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"]
}
]
}
Run Code Online (Sandbox Code Playgroud)
结果:
添加一个SubmitField到你的OrderForm:
submit_something = SubmitField((u'Add something'))
Run Code Online (Sandbox Code Playgroud)
然后从您的视图中调用它,并使用append_entry以下方法FieldList:
if form.submit_something.data:
form.order_entries.append_entry()
return render_template('yourtemplate.html', form=form)
Run Code Online (Sandbox Code Playgroud)
希望有帮助!