【问题标题】:sqlalchemy .contains() matches only first elementsqlalchemy .contains() 仅匹配第一个元素
【发布时间】:2020-10-09 07:12:42
【问题描述】:

我在falsk-sqlalchemy 中有以下模型/表格:

class MainTerm(db.Model):
    __tablename__ = 'main_term'
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String)


terms_in_gzt = db.Table('terms_in_gzt',
    db.Column('gzt_term_id', db.Integer, db.ForeignKey('gzt_term.id')),
    db.Column('gazetteer_id', db.Integer, db.ForeignKey('gazetteer.id')),
)

class Gazetteer(db.Model):
    __tablename__ = 'gazetteer'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    terms = db.relationship('GztTerm', secondary=terms_in_gzt, backref='gazetteers', lazy='dynamic')

class GztTerm(db.Model):
    __tablename__ = 'gzt_term'
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String)

我目前正在运行 sqlite(sqlite 版本 '3.32.3'),但后来打算使用 postgresql。因此,postgres 的解决方案比 sqlite 的解决方案更重要。

我有这个连接查询来查询与Gazetteer.id == 3 关联的GztTerm 条目的text 列:

joinq = db.session.query(GztTerm.text).join(terms_in_gzt).join(Gazetteer).filter(Gazetteer.id == 3)
joinq.all()

结果如下:

[('IBM'), ('Lund'), ('Bluetooth')]

当我现在打电话时:

binary_expression = MainTerm.text.contains(joinq)
res = db.session.query(MainTerm).filter(binary_expression).all()

然后我只得到第一个元素 “IBM” 的结果。 "Bluetooth""Lund" 的结果缺失,即使它们在数据库中。当我更改查询时,我总是只得到joinq 的第一个元素的结果。

所以我的问题是:
我需要改变什么,我的BinaryExpression MainTerm.text.contains(joinq) 考虑了joinq 的所有元素?

提前致谢!


编辑:

以下用于构造 binary_expression 的代码归档了所需的行为:

from sqlalchemy import or_
binary_expression = or_(MainTerm.text.contains(text) for text in joinq)

不过,这感觉更像是一种 hack,而且可能效率不高。
有没有办法仅使用 sqlalchemy 来归档相同的行为而无需循环? em>

【问题讨论】:

  • 你用的是什么数据库?
  • 打印查询本身,您可能会发现它生成 SQL 代码的两种方式存在差异
  • @IljaEverilä 我正在使用 sqlite 版本“3.32.3”。这对其他数据库会有所不同吗?
  • @Peter 打印出来到底是什么意思?
  • query = db.session.query(MainTerm).filter(binary_expression); result = query.all()。您可以打印查询对象以查看其背后的原始 SQL。

标签: python sqlalchemy flask-sqlalchemy


【解决方案1】:

我最终将column_property 添加到GztTerm

from sqlalchemy.orm import column_property

class GztTerm(db.Model):
    __tablename__ = 'gzt_term'
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String)
    text_like = column_property('%'+text+'%')

这使我能够使用like 而不是contains(它本身基于like)和any_ (感谢Ilja Everilä 的这个想法!)

最终查询如下所示:

from sqlalchemy import any_
joinq  = db.session.query(GztTerm.text_like).join(terms_in_gzt).join(Gazetteer).filter(Gazetteer.id == 3)
binary_expression = MainTerm.text.like(any_(joinq))
res = db.session.query(MainTerm).filter(binary_expression).all()

要获得补码notlikeall_ 用于二进制表达式:

from sqlalchemy import all_
binary_expression = MainTerm.text.notlike(all_(joinq))

希望这对某人有帮助!

【讨论】:

    猜你喜欢
    • 2021-12-08
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多