返回介绍

搜索表单

发布于 2025-01-02 21:53:57 字数 4059 浏览 0 评论 0 收藏 0

的确有些激进。 我上面做的保持通用性的工作涉及到几个高级主题,因此可能需要一些时间才能完全理解。 现在我有一套完整的系统来处理用户动态的自然语言搜索。 所以现在需要做的是将所有这些功能与应用集成在一起。

基于网络搜索的一种相当标准的方法是在 URL 的查询字符串中将搜索词作为 q 参数的值。 例如,如果你想在 Google 上搜索 Python ,并且想要节约少许时间,则只需在浏览器的地址栏中输入以下 URL 即可直接查看结果:

https://www.google.com/search?q=python

允许将搜索完全封装在 URL 中是很好的,因为这方便了与其他人共享,只要点击链接就可以访问搜索结果。

请允许我向你介绍一种区别于以前的 Web 表单的处理方式。 我曾经使用 POST 请求来提交表单数据,但是为了实现上述搜索,表单提交必须以 GET 请求发送,这是一种请求方法,当你在浏览器中输入网址或点击链接时,就是 GET 请求。 另一个有趣的区别是搜索表单将存在于导航栏中,因此它将会出现应用的所有页面中。

这里是搜索表单类,只有 q 文本字段:

app/main/forms.py :搜索表单。

from flask import request

class SearchForm(FlaskForm):
    q = StringField(_l('Search'), validators=[DataRequired()])

    def __init__(self, *args, **kwargs):
        if 'formdata' not in kwargs:
            kwargs['formdata'] = request.args
        if 'csrf_enabled' not in kwargs:
            kwargs['csrf_enabled'] = False
        super(SearchForm, self).__init__(*args, **kwargs)

q 字段不需要任何解释,因为它与我以前使用的其他文本字段相似。在这个表单中,我不需要提交按钮。对于具有文本字段的表单,当焦点位于该字段上时,你按下 Enter 键,浏览器将提交表单,因此不需要按钮。我还添加了一个 __init__ 构造函数,它提供了 formdatacsrf_enabled 参数的值(如果调用者没有提供它们的话)。 formdata 参数决定 Flask-WTF 从哪里获取表单提交。缺省情况是使用 request.form ,这是 Flask 放置通过 POST 请求提交的表单值的地方。通过 GET 请求提交的表单在查询字符串中传递字段值,所以我需要将 Flask-WTF 指向 request.args ,这是 Flask 写查询字符串参数的地方。你是否还记得的,表单默认添加了 CSRF 保护,包含一个 CSRF 标记,该标记通过模板中的 form.hidden_tag() 构造添加到表单中。为了使搜索表单运作,CSRF 需要被禁用,所以我将 csrf_enabled 设置为 False ,以便 Flask-WTF 知道它需要忽略此表单的 CSRF 验证。

由于我需要在所有页面中都显示此表单,因此无论用户在查看哪个页面,我都需要创建一个 SearchForm 类的实例。 唯一的要求是用户登录,因为对于匿名用户,我目前不会显示任何内容。 与其在每个路由中创建表单对象,然后将表单传递给所有模板,我将向你展示一个非常有用的技巧,当你需要在整个应用中实现一个功能时,可以消除重复代码。 回到 第六章 ,我已经使用了 before_request 处理程序, 来记录每个用户上次访问的时间。 我要做的是在同样的功能中创建我的搜索表单,但有一点区别:

app/main/routes.py :在请求处理前的处理器中初始化搜索表单。

from flask import g
from app.main.forms import SearchForm

@bp.before_app_request
def before_request():
    if current_user.is_authenticated:
        current_user.last_seen = datetime.utcnow()
        db.session.commit()
        g.search_form = SearchForm()
    g.locale = str(get_locale())

在这里,当用户已认证时,我会创建一个搜索表单类的实例。当然,我需要这个表单对象一直存在,直到它可以在请求结束时渲染,所以我需要将它存储在某个地方。那个地方就是 Flask 提供的 g 容器。这个 g 变量是应用可以存储需要在整个请求期间持续存在的数据的地方。在这里,我将表单存储在 g.search_form 中,所以当请求前置处理程序结束并且 Flask 调用处理请求的 URL 的视图函数时, g 对象将会是相同的,并且表单仍然存在。请注意,这个 g 变量对每个请求和每个客户端都是特定的,因此即使你的 Web 服务器一次为不同的客户端处理多个请求,仍然可以依靠 g 来专用存储各个请求的对应变量。

下一步是将表单渲染成页面。 我在上面说过,我想在所有页面中展示这个表单,所以更有意义的是将其作为导航栏的一部分进行渲染。 事实上,这很简单,因为模板也可以看到存储在 g 变量中的数据,所以我不需要在所有 render_template() 调用中将表单作为显式模板参数添加进去。以下是我如何在基础模板中渲染表单的代码:

app/templates/base.html :在导航栏中渲染搜索表单。

            ...
            <div id="bs-example-navbar-collapse-1">
                <ul>
                    ... home and explore links ...
                </ul>
                {% if g.search_form %}
                <form method="get"
                        action="{{ url_for('main.search') }}">
                    <div>
                        {{ g.search_form.q(size=20, class='form-control',
                            placeholder=g.search_form.q.label.text) }}
                    </div>
                </form>
                {% endif %}
                ...

只有在定义了 g.search_form 时才会渲染表单。 此检查是必要的,因为某些页面(如错误页面)可能没有定义它。 这个表单与我之前做过的略有不同。 我将 method 属性设置为 get ,因为我希望表单数据作为查询字符串,通过 GET 请求提交。 另外,我创建的其他表单 action 属性为空,因为它们被提交到渲染表单的同一页面。 而这个表单很特殊,因为它出现在所有页面中,所以我需要明确告诉它需要提交的地方,这是专门用于处理搜索的新路由。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文