SQLAlchemy查询返回所有联接行的计数,而不是按联接行分组



我正在构建一个CRUD应用程序,并试图显示一个post"标签";,在使用该标签的帖子数量旁边各有一个数字,并按帖子数量排序。我有一个用于posts的表,一个用于tags的表和一个名为posts_tags的联接表。当我执行我认为应该完成的查询时,它会显示posts_tags表中所有行的计数,而不仅仅是与每个标记关联的行的计数。在下面的图像中;测试";标签已经在3个帖子上使用;测试2";在1上(这是应该显示在它们旁边的数字),但正如你所看到的,我得到了4:

显示标签的错误投递计数

我的标签表与posts_tags表有关系,允许我使用";Tag.tagged_post_ids"在查询中:

`

class Tag(db.Model):
""" Model for tags table """
__tablename__ = "tags"
id = db.Column(
db.Integer,
primary_key=True,
autoincrement=True
)
tag = db.Column(
db.String(30),
nullable=False,
unique=True
)
description = db.Column(
db.Text,
nullable=False
)
tagged_post_ids = db.relationship(
"PostTag"
)

`

这是我写的SQLA查询:

`

tags = db.session.query(Tag.tag, func.count(Tag.tagged_post_ids).label("count")).group_by(Tag.tag).order_by(func.count(Tag.tagged_post_ids)).all()

`

我已经成功地在SQL:中构建了查询

SELECT tags.tag, COUNT(posts_tags.post_id) FROM tags JOIN posts_tags ON posts_tags.tag_id = tags.id GROUP BY tags.tag ORDER BY COUNT(posts_tags.post_id) DESC;

我的主要问题是试图将其转化为SQLAlchemy。我觉得我的查询是SQL查询的1对1,但它不起作用!如有任何帮助,我们将不胜感激。

编辑:添加我的Post模型和PostTag(加入)模型:

class Post(db.Model):
""" Model for posts table """
__tablename__ = "posts"
id = db.Column(
db.Integer,
primary_key=True,
autoincrement=True
)
user_id = db.Column(
db.Integer,
db.ForeignKey("users.id")
)
title = db.Column(
db.Text,
nullable=False
)
content = db.Column(
db.Text
)
url = db.Column(
db.Text
)
img_url = db.Column(
db.Text
)
created_at = db.Column(
db.DateTime,
nullable=False,
default=db.func.now()
)
score = db.Column(
db.Integer,
nullable=False,
default=0
)
tags = db.relationship(
"Tag",
secondary="posts_tags",
backref="posts"
)
comments = db.relationship(
"Comment",
backref="post"
)
@property
def tag_list(self):
""" Builds comma separated list of tags for the post. """
tag_list = []
for tag in self.tags:
tag_list.append(tag.tag)

return tag_list
class PostTag(db.Model):
""" Model for join table between posts and tags """
__tablename__ = "posts_tags"
post_id = db.Column(
db.Integer,
db.ForeignKey("posts.id"),
primary_key=True
)
tag_id = db.Column(
db.Integer,
db.ForeignKey("tags.id"),
primary_key=True
)

如果使用backref,则只需要定义关系的一侧。实际上,我不知道当你在relationship上使用func.count时会发生什么,我只在列上使用它。这里有几个选项。当有0篇带有该标记的帖子时,需要一个外部联接来捕捉这种情况,否则使用内部联接,结果中就会缺少该标记。在第一个示例中,我还使用func.coalesceNULL转换为0

class Tag(Base):
""" Model for tags table """
__tablename__ = "tags"
id = Column(
Integer,
primary_key=True,
autoincrement=True
)
tag = Column(
String(30),
nullable=False,
unique=True
)
# Redundant
#    tagged_post_ids = relationship(
#        "PostTag"
#    )

class Post(Base):
""" Model for posts table """
__tablename__ = "posts"
id = Column(
Integer,
primary_key=True,
autoincrement=True
)

title = Column(
Text,
nullable=False
)
tags = relationship(
"Tag",
secondary="posts_tags",
backref="posts"
)

@property
def tag_list(self):
""" Builds comma separated list of tags for the post. """
tag_list = []
for tag in self.tags:
tag_list.append(tag.tag)
return tag_list
class PostTag(Base):
""" Model for join table between posts and tags """
__tablename__ = "posts_tags"
post_id = Column(
Integer,
ForeignKey("posts.id"),
primary_key=True
)
tag_id = Column(
Integer,
ForeignKey("tags.id"),
primary_key=True
)

metadata.create_all(engine)
with Session(engine) as session, session.begin():
# With subquery
tag_subq = select(
PostTag.tag_id,
func.count(PostTag.post_id).label("post_count")
).group_by(
PostTag.tag_id
).order_by(
func.count(PostTag.post_id)
).subquery()
q = session.query(
Tag.tag,
func.coalesce(tag_subq.c.post_count, 0)
).outerjoin(
tag_subq,
Tag.id == tag_subq.c.tag_id
).order_by(
func.coalesce(tag_subq.c.post_count, 0))
for (tag_name, post_count) in q.all():
print (tag_name, post_count)

# With join
q = session.query(
Tag.tag,
func.count(PostTag.post_id).label('post_count')
).outerjoin(
PostTag,
Tag.id == PostTag.tag_id
).group_by(
Tag.id
).order_by(
func.count(PostTag.post_id))
for (tag_name, post_count) in q.all():
print (tag_name, post_count)

最新更新