我具有部分动态功能的static from,您可以在其中添加更多<input>
字段以在单击按钮时添加标签。
我的表单正在对所有静态表单字段和jQuery基于此great answer from nsfyn55生成的<input>
字段使用WTForms模板,以添加更多标签。
前端工作得很好,但是我受困于python中的验证,其中validate_on_submit()
一直由于未知原因而失败。
我怀疑这与模板的使用和jQuery生成的<input>
字段的混合使用有关,从而以某种方式破坏了我的验证。
另一个原因可能是我,我不了解how to use AJAX with flask properly并以某种方式处理了AJAX POST。
MVCE:
app.py
@app.route(BASEURL + '/new', methods=['GET', 'POST'])
def new():
form = Form()
global metadata
data = dict()
if form.validate_on_submit():
keyword1 = request.form['keyword-1']
keyword2 = request.form['keyword-2']
keyword3 = request.form['keyword-3']
keywords = []
if keyword1: keywords.append(keyword1)
if keyword2: keywords.append(keyword2)
if keyword3: keywords.append(keyword3)
data.update({
'given_name': form.abstract.data,
'family_name': form.description.data,
'keywords': keywords,
})
filename = 'data.json'
with open('data/' + filename, 'w') as file:
file.write(json.dumps(metadata, indent=4, sort_keys=False))
class Form(FlaskForm):
given_name = StringField()
family_name = StringField()
new.html
<html>
<head>
<title>New</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="{{ url_for('static', filename='js/form.js') }}"></script>
</head>
<body>
<form method='POST' action='{{ url_for('new') }}'>
{{ form.csrf_token }}
{% from "_formhelpers.html" import render_field %}
<dl>
{{ render_field(form.given_name) }}
{{ render_field(form.family_name) }}
<div id="keywordsTest"></div>
<button onclick="keywordField()">+</button>
</dl>
<input type="submit" value="Submit">
</form>
<script>
var index = 0;
function keywordField(){
if(index<3){
index+=1;
$('<input>').attr({
type: 'text',
id: 'keyword-' + index ,
name: 'keyword-' + index,
placeholder: 'keyword' + index
}).appendTo('#keywordsTest');
}
return false
}
$(keywordField)
</script>
</body>
</html>
form.js
$(document).ready(function() {
$('form').on('submit', function(event) {
$.ajax({
data : {
keyword1 : $('#keyword-1').val(),
keyword2 : $('#keyword-2').val(),
keyword3 : $('#keyword-3').val()
},
type : 'POST',
url : '/register/new'
});
event.preventDefault();
});
});
答案 0 :(得分:1)
@ADyson的评论解释了您遇到的一个具体问题,您应该将代码真正更改为:
$.ajax({
data : {
"keyword-1" : $('#keyword-1').val(),
"keyword-2" : $('#keyword-2').val(),
"keyword-3" : $('#keyword-3').val()
},
但这并不能真正解决您的核心问题。您正在使用WTForms,大概是因为您想使用其固有的服务器端表单验证库。目前您的Form
类未执行任何验证,因此行form.validate_on_submit()
将不执行任何操作。插入以下内容:
from wtforms.validators import InputRequired
...
given_name = StringField(validators=[InputRequired()])
至少现在您可以测试您的代码,以便它尝试执行一些基本的验证服务。
但这是另一个问题。您的Form
类希望处理两个表单字段; given_name
和family_name
,但是您通过POST
通过AJAX获得的数据不包含这两个字段,实际上,您要发布的数据被指定为:
data : {
"keyword-1" : $('#keyword-1').val(),
"keyword-2" : $('#keyword-2').val(),
"keyword-3" : $('#keyword-3').val()
},
就这样-因为您在此处直接和明确指定了数据,因此您不会自动在HTML中发送其他表单字段。
烧瓶路径在其core
级别接收一个名为request
的对象。如果您插入
def new():
print("the data supplied in post request form is: ", request.form)
然后,您可以调试在传输数据中看到的内容。此请求将发生form.validate_on_submit()
失败,并显示错误{'given_name: ['This field is required.']}
。即使您以表格的形式提供此字段,也会由于未显式传递它而出错。当您执行form = Form()
时,form
中将填充来自request
的数据。
修复此问题后,代码KeyError
也将受到影响,因为如果某些字段是可选的,或者用户尚未添加第二个或第三个可选输入字段,则:
keyword2 = request.form['keyword-2']
将不存在,所以尝试类似
keyword2 = request.form.get('keyword-2', None)
因为至少有一个转义子句。
我很欣赏您不一定要使用Webargs而不是WTForms来使用我建议的方法,但是在您的示例中,包含WTForms绝对没有任何意义(也许除了HTML呈现客户端之外)。当您访问提交的值时,您直接在request.form
中访问它们,这完全避开了服务器端的验证,并使form=Form()
完全多余。
如果您知道最多可以获取3个关键字,则可以使用隐藏字段预先填充表单:
class Form(FlaskForm):
given_name = StringField(validators=[InputRequired()], render_kw={'placeholder': 'Given Name'})
family_name = StringField(render_kw={'placeholder': 'Surname'})
keyword1 = StringField(validators=[Optional()], render_kw={'placeholder': 'k1'})
keyword2 = StringField(validators=[Optional()], render_kw={'style': 'display:none;', 'placeholder': 'k2'})
keyword3 = StringField(validators=[Optional()], render_kw={'style': 'display:none;', 'placeholder': 'k3'})
在HTML上显示如下表单:
{{ form.given_name }}
{{ form.family_name }}
{{ form.keyword1 }}
{{ form.keyword2 }}
{{ form.keyword3 }}
因为只有render_kw
可以看到Keyword1,但是您可以轻松地编写一些JS来单击按钮,并更改Keyword2和Keyword3上none
的显示属性,类似于上面的操作,但情况并非如此,因为它只需要getElementById并设置style属性即可。
单击submit
时,您无需拦截它并执行AJAX查询(意味着“ form.js”可以完全删除),您可以将POST作为常规表单操作执行。
WTForms将根据您的班级对其进行验证,并将数据填充为form.keyword2.data
等。