SQLAlchemy:多对多关系查询中的过滤计数

时间:2015-04-12 17:48:50

标签: python sqlalchemy flask-sqlalchemy

在我的Flask应用程序中,Documents和Tokens之间存在多对多关系:

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为None 的相关标记的数量排序(降序)。

到目前为止,我已经找到了如何通过相关代币的数量来订购文档:

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的Tokens。这是许多尝试失败的尝试之一:

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的新手...非常感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

  • 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& #34;,"文件"加入" DocTokens" ON" Document" .id =" DocTokens" .document_id \ nWHERE" Token" .is_gold IS NULL GROUP BY" Document" .id ORDER BY总DESC'

更新:如果你不确定从查询对象生成什么样的SQL,你总是可以用str检查它,即

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