【问题标题】:SQLAlchemy: filtering count in many-to-many relationship querySQLAlchemy:多对多关系查询中的过滤计数
【发布时间】:2015-04-12 17:48:49
【问题描述】:

在我的 Flask 应用中,文档和令牌之间存在多对多的关系:

DocTokens = db.Table(
    'DocTokens',
    db.Column('token_id', db.Integer, db.ForeignKey('Token.id')),
    db.Column('document_id', db.Integer, db.ForeignKey('Document.id')),
    )

class Token(db.Model):
    __tablename__ = 'Token'
    id = db.Column(db.Integer, primary_key=True)
    ...
    is_gold = db.Column(db.Boolean, default=None)

class Document(db.Model):
    __tablename__ = 'Document'
    id = db.Column(db.Integer, primary_key=True)
    ...
    tokens = db.relationship(
        'Token',
        secondary=DocTokens,
        backred=db.backref('documents', lazy='dynamic'),
        )

我想构建一个文档查询,按相关令牌的数量排序(降序)其中 Token.is_gold 为无

到目前为止,我已经弄清楚了如何按相关令牌的数量对文档进行排序:

db.session.query(
    Document,
    func.count(DocTokens.c.token_id).label('total')
    ).join(DocTokens).group_by(Document).order_by('total DESC')

但是,我似乎无法使该计数仅包括 Token.is_gold 为 None 的令牌。这是许多失败的尝试之一:

db.session.query(
    Document,
    func.count(DocTokens.c.token_id)
    .filter(Token.is_gold.is_(None)).label('total')
    ).join(DocTokens).group_by(Document).order_by('total DESC')

它抛出了以下错误:

AttributeError: Neither 'count' object nor 'Comparator' object has an attribute 'filter'

以下是我尝试建模的一些 StackOverflow 解决方案(包括涉及子查询和混合属性的解决方案):

我对 SQL/SQLAlchemy 还很陌生...非常感谢任何帮助!

【问题讨论】:

  • 你能用普通的sql表达你的查询吗?
  • 感谢您在我回复您的评论之前回答问题。我尝试了几个小时来制定 sql,但我无法让它工作......非常感谢!

标签: python sqlalchemy flask-sqlalchemy


【解决方案1】:
  • label 应该应用于func.count(DocTokens.c.token_id),而不是过滤器对象。您在第一个查询中是正确的,但在第二个查询中却没有。

  • filterquery对象的方法,所以必须写成:

    db.session.query(...).join(...).filter(...).group_by(...).order_by(...)
    
  • 过滤器应用于来自Token 的列,因此它必须包含在联接中。

因此,如下编写的查询不会给您错误:

r = db.session.query(Document,
                  func.count(Token.id).label('total'))\
    .join(DocTokens).join(Token)\
    .filter(Token.is_gold.is_(None))\
    .group_by(Document)\
    .order_by('total DESC')

这将产生以下sql(使用sqlite作为后端)

'SELECT "Document".id AS "Document_id", count("DocTokens".token_id) AS total \nFROM "Token", "Document" JOIN "DocTokens" ON "Document".id = "DocTokens".document_id \nWHERE "Token".is_gold IS NULL GROUP BY "Document".id ORDER BY total DESC'

更新:如果您不确定查询对象会生成什么 sql,您可以随时使用 str 检查它,即

如果我在示例查询中运行 str(r),它会打印上面引用的 sql。

【讨论】:

    猜你喜欢
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 2018-02-24
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多