如何验证通过 AJAX 提交的 web2py 表单?

How to validate a web2py form submitted via AJAX?

我正在尝试使用 web2py 的 ajax 函数作为 explained in the book 提交表单,但使用 FORM 而不是 SQLFORM 因为我不想要数据存储在数据库中。

ajax_test.html

{{extend "layout.html"}}
<h2>Form</h2>
{{=form}}
<script>
  jQuery("#myform").submit(function() {
    ajax("{{=URL('ajax_test')}}",
         ["mytext"], "output");
    return false;
  });
</script>
<h2>Output</h2>
<div id="output"></div>

里面的控制器default.py:

def ajax_test():
    form = FORM(
        INPUT(_type="text", _name="mytext", _id="mytext",
              requires=IS_NOT_EMPTY()),
        INPUT(_type="submit"),
        _id="myform"
    )

    if request.ajax:
        if form.accepts(request.vars, session):
            return DIV("Form submitted.")
        elif form.errors:
            return TABLE(*[TR(k, v) for k, v in form.errors.items()])
        else:
            return DIV("Couldn't check form.")

    return dict(form=form)

提交表单时 (request.ajax == True),form.acceptsform.errors return False。即使我通过 request.vars.mytext 访问用户的输入,我也需要自己验证它而不是使用 web2py 的功能。

我错过了什么?

当你将session对象传递给form.accepts()时,它会通过在表单中​​添加一个隐藏的_formkey字段来自动实现跨站请求伪造保护。提交表单时,将这个隐藏字段的值与session中存储的值进行比较,匹配失败则不接受表单。

您的代码有两个问题。首先,只有在有 Ajax 请求时才调用 form.accepts,因此 _formkey 不会生成并包含在原始表单中。要更正该问题,请尝试以下操作:

form.process()
if request.ajax:
    if form.accepted:

form.process() 只是 form.accepts(request, session) 的快捷方式。在上面,它甚至在创建表单时的初始非 Ajax 调用中也会被调用。这将生成 _formkey 值并将其存储在会话中。

其次,您的 Javascript 代码不会提交整个表单,而只会提交 mytext 字段,因此隐藏的 _formkey 值将不会回传到服务器。结果,表单不被接受(在这种情况下,web2py 不显示错误,因为这种失败通常是犯规的结果)。

我不确定它是否记录在案,但 ajax() 函数的第二个参数可以改为 jQuery 选择器,这将导致所选元素内的所有表单元素被序列化并提交。所以,试试:

    ajax('{{=URL('ajax_test')}}', '#myform', 'output');

#myform 选择器将导致整个表单被序列化,包括 form 对象中包含的隐藏字段。