【问题标题】:Use a "phrase search" in flask admin在烧瓶管理员中使用“短语搜索”
【发布时间】:2015-10-20 09:38:02
【问题描述】:

我正在使用 Flask-Admin,我对此非常满意。

docs 显示了几个可用于搜索预定义字段的选项。我想让我的用户使用引号进行搜索,例如:

"some phrase of which the order should be intact"

如何使用 Flask-Admin 做到这一点?

【问题讨论】:

    标签: flask flask-admin


    【解决方案1】:

    在 Flask-Admin 1.3.0 中,您可以在管理视图类中覆盖 _apply_search 方法。请参阅下面非常简单的代码示例 - 主要取自 Flask-Admin sqla 示例 app.py。

    本质上,您希望为您的 column_searchable_list 中的列生成类似于 %Your Phrase Here% 的 SQL。 _apply_search 的标准行为是将搜索输入文本拆分为空格,并为结果数组中的每个术语生成类似 SQL 的片段。

    相反,您可以使用正则表达式查看是否输入了带引号的字符串,提取引号内的短语,创建适当的 SQL 类片段,然后将其传递给生成查询的代码。

    您也可以执行类似的操作来实现短语过滤 - 请参阅下面代码中的类 FilterPhrase 以及它在 column_filters 列表定义中的使用方式。

    对于更复杂的短语搜索,您可以使用 Whoosh 之类的东西,Postgres 的内置短语搜索功能 text searching(可能与 SQLAlchemy-Searchable 结合使用)甚至是 Elasticsearch

    # coding: utf-8
    __author__ = 'Paul'
    
    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    from sqlalchemy import or_
    from flask.ext.admin import Admin
    from flask.ext.admin.contrib.sqla import ModelView
    from flask.ext.admin.babel import lazy_gettext
    from flask.ext.admin.contrib.sqla.filters import BaseSQLAFilter
    import re
    
    app = Flask(__name__)
    
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
    app.config['SQLALCHEMY_ECHO'] = True
    db = SQLAlchemy(app)
    
    
    @app.route('/')
    def index():
        return '<a href="/admin/">Click me to get to Admin!</a>'
    
    
    class Post(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(255))
        content = db.Column(db.Text, nullable=False)
    
        def __unicode__(self):
            return self.title
    
    
    class FilterPhrase(BaseSQLAFilter):
        def apply(self, query, value, alias=None):
            stmt = "%{phrase}%".format(phrase=value)
            return query.filter(self.get_column(alias).ilike(stmt))
    
        def operation(self):
            return lazy_gettext('phrase')
    
    
    class PostAdmin(ModelView):
        column_searchable_list = ['title', 'content']
    
        column_filters = (
            FilterPhrase(Post.title, "Title"),
            FilterPhrase(Post.content, "Content"),
        )
    
        def _apply_search(self, query, count_query, joins, count_joins, search):
    
            phrases = re.findall(r'"([^"]*)"', search)
    
            if len(phrases) == 0:
                return super(PostAdmin, self)._apply_search(query, count_query, joins, count_joins, search)
    
            stmt = "%{phrase}%".format(phrase=phrases[0])
    
            # The code below is taken directly from the base _apply_search
            filter_stmt = []
            count_filter_stmt = []
    
            for field, path in self._search_fields:
                query, joins, alias = self._apply_path_joins(query, joins, path, inner_join=False)
    
                count_alias = None
    
                if count_query is not None:
                    count_query, count_joins, count_alias = self._apply_path_joins(count_query,
                                                                                   count_joins,
                                                                                   path,
                                                                                   inner_join=False)
    
                column = field if alias is None else getattr(alias, field.key)
                filter_stmt.append(column.ilike(stmt))
    
                if count_filter_stmt is not None:
                    column = field if count_alias is None else getattr(count_alias, field.key)
                    count_filter_stmt.append(column.ilike(stmt))
    
            query = query.filter(or_(*filter_stmt))
    
            if count_query is not None:
                count_query = count_query.filter(or_(*count_filter_stmt))
    
            return query, count_query, joins, count_joins
    
    
    # Create admin
    admin = Admin(app, name='Phrase Searching')
    admin.add_view(PostAdmin(model=Post, session=db.session, category='Blog', name='Posts'))
    
    
    def build_db():
        sample_posts = [
            {
                'title': "de Finibus Bonorum et Malorum - Part I",
                'content': "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut"
            },
            {
                'title': "de Finibus Bonorum et Malorum - Part II",
                'content': "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque"
            },
            {
                'title': "de Finibus Bonorum et Malorum - Part III",
                'content': "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium"
            }
        ]
    
        db.drop_all()
        db.create_all()
    
        for row in sample_posts:
            post = Post(**row)
            db.session.add(post)
    
        db.session.commit()
    
    
    if __name__ == '__main__':
        build_db()
        app.run()
    

    【讨论】:

    • 由于您似乎是烧瓶管理员专业人士:以防万一您知道答案,我开始对this question 进行赏金。 :)
    猜你喜欢
    • 1970-01-01
    • 2018-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 2013-12-25
    • 2020-08-11
    相关资源
    最近更新 更多