2015-04-12 83 views
1

在我的瓶的应用程序,有许多到许多文件和标记之间的关系:的SQLAlchemy:在许多一对多的关系查询过滤计数

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

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

+0

你能表达你的查询在纯sql吗? –

+0

感谢您在回复您的评论之前回答此问题。我尝试了几个小时来制定SQL,但我无法得到它的工作......非常感谢! – NTS

回答

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", "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。

+0

这很好用=)并且,谢谢你的解释! – NTS

+0

很高兴帮助。用小提示更新答案。 –

相关问题