【问题标题】:Correct way to handle pagination with form submission?使用表单提交处理分页的正确方法?
【发布时间】:2015-01-26 11:16:14
【问题描述】:

我有一个用于在搜索页面上进行搜索的表单:

<form action="{{ url_for('searchresults') }}" method="get" name="noname" id="theform">
    {{ form2.page(id="hiddenpage") }}
    ... some form inputs
    <button id = "mybutton" type = "submit" >Apply</button>
</form>

表单是SearchForm,其中

class SearchForm(Form):
    page = HiddenField()
    categories = SelectMultipleField(u'Text', validators=[Optional()])
    # some other stuff...

searchresults 的视图处理表单:

@app.route('/searchresults', methods=['GET'])
def searchresults():
    form = SearchForm()
    # handle the form and get the search results using pagination
    page = int(request.args.getlist('page')[0])
    results = models.Product.query....paginate(page, 10, False)
    return render_template('searchresults.html', form=form, results=results, curpage=page)

render_template 中的 results 将是我查询的前 10 个结果。在searchresults.html 中,我显示结果,以及用于其他结果的nextprevious 链接。此页面还包含我根据初始提交重新设置的相同搜索表单。目前我正在处理nextprevious 链接使用

<a href="#" onclick="$('#hiddenpage').val( {{ curpage+1 }} ); $('#theform').submit();"> Next </a>

所以next 链接重新提交了相同的初始表单,但page 的值增加了。我对这种方法不太满意,因为当我将鼠标悬停在next 链接上时,我看不到我将被定向到的实际页面。它也开始感觉有点像黑客。有没有更自然的方法来做到这一点?最初提交表单时,我可以使用它来创建所需参数的长字符串,并在呈现的页面中将该字符串用作href=" {{ url_for('searchresults') }}?mystring",但这似乎也不自然。我该如何处理?

【问题讨论】:

    标签: pagination flask wtforms


    【解决方案1】:

    您已将表单配置为以GET 请求的形式提交,因此您实际上不需要通过Javascript 强制重新提交,您可以通过设置nextprev 链接来获得相同的结果到包含表单中所有参数的 URL,并将页面修改为正确的下一页和上一页码。

    url_for() 很容易做到这一点。您添加的任何与路由组件不匹配的参数都将添加到查询字符串中,因此您可以执行以下操作:

    <a href="{{ url_for('searchresults', categories=form.categories.data, page=form.page.data+1) }}"> Next </a>
    

    要记住的一件事是 CSRF。如果您在表单中启用了它,那么您的下一个/上一个 URL 也需要有一个有效的令牌。或者您可以禁用 CSRF,这对于搜索表单可能没问题。

    【讨论】:

    • 嗨米格尔。感谢您的回答。这看起来是一种更好的方法。它让我想到了两个我一直想知道的问题,但这把它们带到了最前沿。 1) 点击您的Next 链接是否等同于提交带有categoriespage 数据的GET 表单?我知道生成的 URL 最终会看起来相同,但是在技术上还有什么不同吗? 2)为什么CSRF在这里很重要?我一直在我的表单中插入 `{{ form.hidden_​​tag() }}`,但并没有真正了解它们如何实现某种形式的安全性。如何给下一个/上一个 URL 一个有效的令牌?
    • 1) 作为GET 请求提交的表单与包含该表单所有字段的常规链接相同。如果您在此表单中有 hidden_link 字段,则您的请求包含一个 CSRF 令牌(如果您在提交搜索时查看设置为您的服务器的 URL,您可以看到该令牌)。 2)我认为 CSRF 对这种情况并不重要,因为请求不能修改您服务器中的任何内容。我会为这个表单禁用它。
    • 攻击者可能想利用您的登录状态在未经您许可的情况下进行某些操作。如果这个搜索表单所做的只是读取一些数据并返回它,并且数据不是用户敏感的,那么 CSRF 就没有必要了。如果数据很敏感,那么也许您应该考虑切换到POST 请求。在这种情况下,您可以在 URL 中保留页码,并且只在表单中提交搜索参数。
    【解决方案2】:

    利用您的表单参数已经存在于 URL 中这一事实,并使用 request.args 将 URL 参数传递到您的表单中:

    form = SearchForm(request.args)
    

    然后,如果您使用 HiddenInput 小部件而不是字符串字段将 page 字段设为 IntegerField

    from wtforms.widgets import HiddenInput
    
    class SearchForm(Form):
        page = HiddenField(widget=HiddenInput, default=1)
    

    您可以在将表单传递到搜索结果页面之前增加 page

    form.page.data += 1
    

    然后,在您的页面中,您只需创建指向下一页的链接:

    <a href="{{ url_for('searchresults', **form.data) }}">Next</a>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-04
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2017-01-22
      • 1970-01-01
      • 1970-01-01
      • 2019-12-17
      相关资源
      最近更新 更多