首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >validate_on_submit()在使用AJAX接收jQuery扩展表单时失败

validate_on_submit()在使用AJAX接收jQuery扩展表单时失败
EN

Stack Overflow用户
提问于 2019-04-09 13:40:20
回答 1查看 579关注 0票数 0

我想做的是

我有一个具有部分动态功能的静态from,您可以在单击按钮时添加更多的<input>字段来添加标记。

问题所在

我的表单是对所有静态表单字段和使用WTForms生成的<input>字段使用jQuery模板来添加更多的标记。

前端运行得很好,但是我仍然坚持在python中进行验证,在那里,validate_on_submit()总是因为一个未知的原因而失败。

我怀疑这与模板的混合使用和jQuery生成的<input>字段有关,不知何故破坏了对我的验证。另一个原因可能是我,不理解如何正确使用AJAX与烧瓶和不知何故地错误处理AJAX的帖子。

MVCE

app.py

代码语言:javascript
复制
@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

代码语言:javascript
复制
<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

代码语言:javascript
复制
$(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();
    });
});
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-04-09 16:40:13

@ADyson的评论解释了您正面临的一个特定问题,即您确实应该将代码更改为:

代码语言:javascript
复制
$.ajax({
        data : {
            "keyword-1" : $('#keyword-1').val(),
            "keyword-2" : $('#keyword-2').val(),
            "keyword-3" : $('#keyword-3').val()
        },

但这并不能真正解决你的核心问题。您正在使用WTForms,大概是因为您希望使用其固有的服务器端表单验证库。目前,您的Form类没有执行任何验证,因此行form.validate_on_submit()将什么也不做。插入以下内容:

代码语言:javascript
复制
from wtforms.validators import InputRequired
...
given_name = StringField(validators=[InputRequired()])

至少现在您可以测试您的代码,以便它尝试执行一些基本的验证服务。

但这是另一个问题。您的Form类希望处理两个表单字段:given_namefamily_name,但是通过AJAX发布的数据并不包含这两个字段中的任何一个,实际上您正在发布的数据指定为:

代码语言:javascript
复制
    data : {
            "keyword-1" : $('#keyword-1').val(),
            "keyword-2" : $('#keyword-2').val(),
            "keyword-3" : $('#keyword-3').val()
        },

就这样--您不会自动在HTML中发送其他表单字段,因为您已经在这里直接并显式地指定了数据。

core级别,烧瓶路由接收一个名为request的对象。如果插入行

代码语言:javascript
复制
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的影响,因为如果某些字段是可选的,或者用户没有添加第二个或第三个可选输入字段,那么:

代码语言:javascript
复制
keyword2 = request.form['keyword-2']

将不存在,所以请尝试类似的

代码语言:javascript
复制
keyword2 = request.form.get('keyword-2', None)

因为那至少有个免责条款。

我理解您不一定想使用我以前建议的方法来使用Webargs,而不是WTForms,但是在这里的示例中,WTForms的包含绝对没有任何用处(除了HTML呈现客户端之外)。当您访问提交的值时,您将直接在request.form中访问它们,这将完全绕过服务器端验证,并使form=Form()完全冗余。

简单解

如果您知道最多需要获取3个关键字,那么您可以使用隐藏字段预填充表单:

代码语言:javascript
复制
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中,表单显示如下:

代码语言:javascript
复制
{{ 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等。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55594285

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档