【问题标题】:python sqlalchemy filter records that all the keys in a list appear in either of two filedspython sqlalchemy过滤器记录列表中的所有键出现在两个字段中的任何一个
【发布时间】:2016-09-06 10:29:19
【问题描述】:

我正在用烧瓶和 Flask-SQLAlchemy 编写一个简单的 BBS 系统。我想实现一个简单的搜索功能,它找出给定列表中所有键出现在两个字段中的任何一个字段中的所有记录:“标题”和“内容”。这是我现在的做法:

# Topic is just a table and has some fields, such as title and content.
keys = keywords.split(' ')
all_topics = set(Topic.query.filter(
    and_(*[Topic.title.like("%" + k + "%") for k in keys])).all())
content_topics = set(Topic.query.filter(
    and_(*[Topic.content.like("%" + k + "%") for k in keys])).all())

# Remove duplicated search result, because the keywords may 
# occur in both title and content.
all_topics.update(content_topics)

但这不是很合适。因为对于一个指定的键,它可以出现在标题或内容中。


更新:

为了更清楚,我想举一个简单的例子。 db 中的记录如下:

 Id |      Title          | Content   
 ---|       ---           | ---  
| 1 | This is a demo      | For test  
| 2 | This is also a demo | Again  
| 3 | This demo test      | HaHa

当我搜索“This test”时,我当前的函数只返回record 3。但我也希望record 1 也能被退回。我应该怎么办?

【问题讨论】:

    标签: python-2.7 flask-sqlalchemy


    【解决方案1】:

    无需为 Python 集合而烦恼 - 让数据库来完成这项工作。所有关键字必须出现在列标题中,或列内容中或列标题和内容的串联中。

    请参阅下面的独立示例。您需要根据您使用的数据库调整定义混合表达式的方式。由于示例使用 SQLite,我使用了 literal_column 将两个字段连接成一个字符串,但其他数据库可能具有 concat 函数。

    from flask import Flask, render_template_string
    from flask_sqlalchemy import SQLAlchemy
    from sqlalchemy import or_, and_
    from sqlalchemy.ext.hybrid import hybrid_property
    from sqlalchemy.sql import literal_column
    from sqlalchemy.sql import expression, functions
    
    app = Flask(__name__)
    app.config['DEBUG'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
    app.config['SQLALCHEMY_ECHO'] = True
    db = SQLAlchemy(app)
    
    
    def build_db():
        db.drop_all()
        db.create_all()
        _items = [
            {'title': 'This is a demo one', 'content': 'For test'},
            {'title': 'This is also a demo two', 'content': 'Again'},
            {'title': 'This demo test three', 'content': 'HaHa'},
        ]
    
        for _item in _items:
            _topic = Topic(**_item)
            db.session.add(_topic)
    
        db.session.commit()
    
    
    class Topic(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        title = db.Column(db.Unicode(length=255), nullable=False)
        content = db.Column(db.Unicode(length=255), nullable=False)
    
        @hybrid_property
        def title_content(self):
            return '{0} {1}'.format(self.title, self.content)
    
        @title_content.expression
        def title_content(cls):
            return literal_column('title || " " || content')
    
    TEMPLATE = '''
        {% for topic in all_topics %}
            <h1>{{topic.title}}</h1>
            <p>{{topic.content}}</p>
            <hr>
        {% endfor %}
    '''
    
    
    @app.route('/')
    def index():
    
        keys = 'This test'.split(' ')
    
        _title_conditions = []
        for name in keys:
            _title_conditions.append(Topic.title.ilike('%{}%'.format(name)))
    
        _content_conditions = []
        for name in keys:
            _content_conditions.append(Topic.content.ilike('%{}%'.format(name)))
    
        _content_concat_topic_conditions = []
        for name in keys:
            _content_concat_topic_conditions.append(Topic.title_content.ilike('%{}%'.format(name)))
    
        all_topics = Topic.query.filter(or_(
            and_(*_content_conditions).self_group(),
            and_(*_title_conditions).self_group(),
            and_(*_content_concat_topic_conditions).self_group(),
        )).all()
    
        for _topic in all_topics:
            print _topic.title
    
        return render_template_string(TEMPLATE, all_topics=all_topics)
    
    @app.before_first_request
    def first_request():
        build_db()
    
    if __name__ == '__main__':
        app.run(debug=True, port=7777)
    

    【讨论】:

    • 抱歉,我的问题不太清楚。我刚刚更新,希望你能明白我的想法并帮助我。
    • 知道了!混合属性是关键!非常感谢您的详细演示。
    猜你喜欢
    • 2021-06-03
    • 2016-04-03
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多