在flask项目中利用ilike进行搜索

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huitailang1991/article/details/78394125

在项目中的表格上方,通常都会添加一个搜索窗口,按输入内容进行搜索。搜索过程是前端输入内容,提交一个表单到相应的路由函数,表单内容在函数中获取是通过request.args.get(‘q’, ”)。我这里搜索表单的id是q,如果获取的内容不存在则内容为空,则不过滤,否则通过Model.query.filter()来过滤相应的内容。下面通过不同部分来看看具体实现。

实现原理是Postgresql的LIKE语句,在项目中是用过SQLAlchemy的ilke方法来实现。

github项目链接

jinja2模板

搜索框是通过宏定义的。

{% import 'macros/form.html' as f with context' %}

    {{ f.search('admin.users') }}

下面看看宏的具体实现办法。templates/macros/form.html。重点看下面两段代码:

...
{# Render a form tag that contains a CSRF token and all hidden fields. #}
{%- macro form_tag(endpoint, fid='', css_class='', method='post') -%}
  <form action="{{ url_for(endpoint, **kwargs) }}" method="{{ method }}"
        id="{{ fid }}" class="{{ css_class }}" role="form">
    {{ form.hidden_tag() }}
    {{ caller () }}
  </form>
{%- endmacro -%}


{# Render a form for searching. #}
{%- macro search(endpoint) -%}
  {% call form_tag(endpoint, method='get') %}
    <label for="q"></label>
    <div class="input-group md-margin-bottom">
      <input type="text" class="form-control"
             id="q" name="q" value="{{ request.args.get('q', '') }}"
             placeholder="Search by typing, then press enter...">
    <span class="input-group-addon">
      <i class="fa fa-fw fa-search"></i>
    </span>
    </div>
  {% endcall %}
{%- endmacro -%}

我们在模板中调用的f.search宏,并传入了admin.users这个endpoint,在search这个宏通过call form_tag这个宏来渲染一个表单,search宏 call内部的内容是放在form_tag的 {{ caller () }}处的,连起来看就是渲染了一个有csrf保护的表单,并且传入有搜索内容的输入窗口,提交出发的动作是路由到admin.users这个视图函数。所以接下来看看试图函数的处理。

views

也是关注代码处理搜索的部分。

@admin.route('/users', defaults={'page': 1})
@admin.route('/users/page/<int:page>')
def users(page):
    search_form = SearchForm()
    bulk_form = BulkDeleteForm()

    sort_by = User.sort_by(request.args.get('sort', 'created_on'),
                           request.args.get('direction', 'desc'))
    order_values = '{0} {1}'.format(sort_by[0], sort_by[1])

    paginated_users = User.query \
        .filter(User.search(request.args.get('q', ''))) \
        .order_by(User.role.asc(), User.payment_id, text(order_values)) \
        .paginate(page, 50, True)

    return render_template('admin/user/index.html',
                           form=search_form, bulk_form=bulk_form,
                           users=paginated_users)

表单提交的内容作为参数传入了.filter(User.search(request.args.get('q', '')))。这里调用了model User的search方法,稍后再分析那边的代码,这里还可以看到,我们最后传入给模板的users其实是有过滤有排序并且分页的对象。

接下来才到搜索的重点,model部分。

User

User是项目中定义用户的模型,通过SQLAlchemy和数据库建立关联。上面说到了搜索是用过User的search方法实现的,代码如下:

    @classmethod
    def search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if not query:
            return ''

        search_query = '%{0}%'.format(query)
        search_chain = (User.email.ilike(search_query),
                        User.username.ilike(search_query))

        return or_(*search_chain)

view函数中传入的表单内容其实就是search函数的query参数(查询信息)。首先我们看下Postgresql的LIKE语句,ILIKE只是让匹配内容与大小写无关,lower(a) LIKE lower(other)和a ILIKE other等效。具体教程

PostgreSQL的LIKE操作符是用来反对使用通配符的模式匹配的文本值。如果搜索表达式可以匹配的模式表达式,LIKE运算将返回true,也就是1。有两个通配符与LIKE运算符一起使用:
    百分号 (%)
    下划线 (_)
百分号表示零个,一个或多个数字或字符。下划线代表一个单一的数字或字符。这些符号可以被组合使用。

那么结合我们传入的内容,search_query查询信息实际就是包含了我们输入内容的字符串。比如输入的是123,那么可能aa123bb, 123df23等都是匹配的内容。然后将查询信息传入ilike,这个ilike是SQLAlchemy中对列使用的方法,就是为了构建pg数据的ILIKE语句。这里为了让输入内容匹配多行,我们通过构建search_chain来让搜索内容匹配两行,并通过or_方法生成关系的连接表达式。

最后就是filter接收这个SQL表达式来筛选内容以达到搜索的目的。

猜你喜欢

转载自blog.csdn.net/huitailang1991/article/details/78394125