每个表单提交只能有一个表单结果。为了能够提交任意和未知数量的输入,您需要借助
WTForm's field enclosures
.
表单
from flask_wtf import FlaskForm
from wtforms import (
FieldList, FormField, DateField FloatField, StringField, SelectField)
from wtforms import Form as NoCsrfForm
class ExpenseItem(NoCsrfForm):
expense_name = StringField('Expense_Item', validators=[DataRequired()])
cost = FloatField('Cost', validators=[DataRequired()])
due_date = DateField('Due Date', format='%Y-%m-%d',
validators=[DataRequired()],
default=datetime.datetime.today().date())
type = SelectField('Role', choices=[
('mutual', 'Mutual'),
('personal#1', 'Personal #1'),
('personal#2', 'Personal #2'),
])
class ExpensesForm(FlaskForm):
"""A collection of expense items."""
items = FieldList(FormField(ExpenseItem), min_entries=1)
我强烈建议您在所有域名前加上
expense
不仅仅是
expense_name
为了理智。
索引文件
<form class="form-horizontal" id="main-form" enctype=multipart/form-data role="form" method="post" action="/">
<input type="hidden" name="count" value="1"/>
{{ form.hidden_tag() }}
{% for expense_item in form.items %}
{{ form.expense_name(placeholder="Expense Name", value="") }}
{{ form.cost(placeholder="Cost", class="cost", value="") }}
{{ form.due_date() }}
{{ form.type(placeholder="Type") }}
{% endfor %}
<button id="b1" class="btn btn-info add-more" type="button">+</button>
<small>Press + to add another set of fields.</small>
<br>
<hr>
<button class="btn btn-sm btn-success" type="submit">Post Expense</button>
</form>
请注意
id
HTML输入字段的属性必须遵循特定的模式。因此,对于通过单击
+
button,您需要重新给
身份证件
其输入字段的属性。
JS
其他的事情都比较容易。现在您需要编写一段.js,它将重新索引
身份证件
每次添加新支出项时,所有输入字段的属性。我使用Javascript的zepto库完成了这项工作。这不好玩,我的.js很糟糕。我在这里能做的最好的就是把整个东西贴上去,希望它能对你有所帮助。我知道这很混乱,但我被加了很多
班
到A
课程
. 为了你,你会想要
开支项目/开支申请
或者无论你选择什么:
// append class-box when new class link clicked
$("#new-class").click(function(event) {
appendClassBox('#classes', {{ newclass|tojson|safe }});
reindexNames('.class-box');
return false;
})
// remove class box when its "remove" link is clicked
$(document).on('click', '#remove-class', function(){
var $toremove = $(this).closest('.class-box');
$toremove.remove();
reindexNames('.class-box');
return false;
})
// add a new class-box
function appendClassBox(container, content) {
$(container).append(content);
// raise last and hence newest class box
raiseClassBox($(container).children().last())
return false;
}
function isNormalInteger(str) {
var n = ~~Number(str);
return String(n) === str && n >= 0;
}
// re-index class-box names
function reindexNames(class_name) {
var $oboxen = $(class_name);
$oboxen.each(function(index) {
// Get all the input fields in the class-box.
var $labels = $oboxen.eq(index).find('label')
var $inputs = $oboxen.eq(index).find(
'input, select, textarea')
// Update the index contained in the name attribute.
$inputs.each(function(idx) {
var $name = $inputs.eq(idx).attr('name').split('-');
// If number in name, grab from number onwards.
var $has_num = false
for (var part in $name) {
if (isNormalInteger($name[part])) {
$has_num = true
$name = $name.slice(part)
$name[0] = index
break
}
}
// Re-index.
if ($has_num == false) {
$name.unshift(index)
}
var $prefix = 'questions'
if (class_name == '.class-box') {
$prefix = 'classes'
}
$name.unshift($prefix)
if (idx > 0) {
$labels.eq(idx - 1).attr('for', $name.join('-'));
}
$inputs.eq(idx).attr('id', $name.join('-'));
$inputs.eq(idx).attr('name', $name.join('-'));
})
})
}
VIEW
@main_blueprint.route('/', methods=['GET', 'POST'])
def index():
form = ExpensesForm()
# Iterate over a collection of new expense items.
if form.validate_on_submit():
for item in form.items.data:
print(item['expense_name'])
print(item['cost'])
print(item['due_date'])
print(item['type'])