我想做的是
我有一个具有部分动态功能的静态from,您可以在单击按钮时添加更多的<input>字段来添加标记。
问题所在
我的表单是对所有静态表单字段和使用WTForms生成的<input>字段使用jQuery模板来添加更多的标记。
前端运行得很好,但是我仍然坚持在python中进行验证,在那里,validate_on_submit()总是因为一个未知的原因而失败。
我怀疑这与模板的混合使用和jQuery生成的<input>字段有关,不知何故破坏了对我的验证。另一个原因可能是我,不理解如何正确使用AJAX与烧瓶和不知何故地错误处理AJAX的帖子。
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();
});
});发布于 2019-04-09 16:40:13
@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,但是通过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代码,以单击按钮并从none on Keyword2和Keyword3中更改display属性,类似于上面所做的操作,尽管不那么简单,因为它只需要getElementById和设置style属性。
单击submit时,您不需要拦截它并执行AJAX查询(意思是'form.js‘可以完全删除),您只需将其作为常规表单操作发布即可。WTForms将根据类对其进行验证,并将数据填充为form.keyword2.data等。
https://stackoverflow.com/questions/55594285
复制相似问题