SQLAlchemy:在多对多关系查询中过滤计数
SQLAlchemy: filtering count in many-to-many relationship query
在我的 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 的代币。这是许多失败尝试之一:
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'
以下是我尝试建模的一些 Whosebug 解决方案(包括涉及子查询和混合属性的解决方案):
- How to order by count of many-to-many relationship in SQLAlchemy?
- Sort by Count of Many to Many Relationship - SQLAlchemy
- SQLAlchemy ordering by count on a many to many relationship
- order by a method contained within a class in SQLAlchemy
我是 SQL/SQLAlchemy 的新手...非常感谢任何帮助!
label
应该应用于 func.count(DocTokens.c.token_id)
,而不是过滤器对象。您在第一个查询中是正确的,但在第二个查询中不是。
filter
是query
对象的一个方法,所以一定要写成:
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。
在我的 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 的代币。这是许多失败尝试之一:
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'
以下是我尝试建模的一些 Whosebug 解决方案(包括涉及子查询和混合属性的解决方案):
- How to order by count of many-to-many relationship in SQLAlchemy?
- Sort by Count of Many to Many Relationship - SQLAlchemy
- SQLAlchemy ordering by count on a many to many relationship
- order by a method contained within a class in SQLAlchemy
我是 SQL/SQLAlchemy 的新手...非常感谢任何帮助!
label
应该应用于func.count(DocTokens.c.token_id)
,而不是过滤器对象。您在第一个查询中是正确的,但在第二个查询中不是。filter
是query
对象的一个方法,所以一定要写成: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。