我有这样的模型:
class User(db.Model):
id = db.Column(UUID_TYPE, primary_key=True)
class Post(db.Model):
id = db.Column(UUID_TYPE, primary_key=True)
private = db.Column(db.Boolean)
class PostSubscription(db.Model):
user_id = db.Column(UUID_TYPE, db.ForeignKey("users.id"))
user = db.relationship(
"User",
backref=db.backref("subscriptions", cascade="all, delete-orphan")
)
post_id = db.Column(UUID_TYPE, db.ForeignKey("posts.id"))
post = db.relationship(
"Post",
foreign_keys=[post_id],
lazy="joined",
backref=db.backref("subscriptions", cascade="all, delete-orphan"),
)
liked = db.Column(db.Boolean)
我有一个查询可以获取用户有权访问的所有私有(private) PostSubscription
,例如
query = (db.session.query(PostSubscription)
.filter(User.id == user_id, Post.private)
.join(PostSubscription.post)
)
我还想在同一查询中获取Post
的总 赞数(以避免N+1 问题) .我的问题是这些点赞本身存储在 PostSubscription 中,这是我首先获取的主要内容。所以整个困惑变得有点 self 参照/循环。
我最初的尝试涉及向 Post
模型添加一个属性,但如上所述,该解决方案存在 N+1 问题,例如
@property
def likes(self):
return db.session.query(PostSubscription).filter_by(
post_id=self.id,
liked=True
).count()
经过一些研究,我意识到我可能需要将 func.count 与 case
结合使用,但我不知道在我的特定用途中如何做到这一点案件。我想做的是:
query = (
db.session.query(
PostSubscription,
func.count(case([Post.subscriptions.liked, Post.id]))
)
.filter(User.id == user_id, Post.private)
.join(PostSubscription.post)
)
但这显然行不通,因为我无法引用这样的关系。这两个表已经加入,我只是不知道如何只获取我已经拥有的 Post
的订阅(链接到我正在获取的 PostSubscription
).
有什么想法吗?
最佳答案
您可以尝试以下 SQLAlchemy 查询:
from sqlalchemy.orm import aliased, contains_eager
u = 1
PS1 = aliased(PostSubscription)
PS2 = aliased(PostSubscription)
query = db.session.query(PS1, func.count(PS2.liked))\
.join(Post, PS1.post_id == Post.id)\
.join(PS2, PS2.post_id == PS1.post_id)\
.options(contains_eager(PS1.post))\
.filter(PS1.user_id == u, Post.private)\
.group_by(PS1.id)
应该给出以下 SQL:
SELECT post.id AS post_id,
post.private AS post_private,
postsubscription_1.id AS postsubscription_1_id,
postsubscription_1.user_id AS postsubscription_1_user_id,
postsubscription_1.post_id AS postsubscription_1_post_id,
postsubscription_1.liked AS postsubscription_1_liked,
Count(postsubscription_2.liked) AS count_1
FROM postsubscription AS postsubscription_1
JOIN post ON postsubscription_1.post_id = post.id
JOIN postsubscription AS postsubscription_2 ON postsubscription_2.post_id = postsubscription_1.post_id
WHERE postsubscription_1.user_id = 1
AND post.private = 1
GROUP BY postsubscription_1.id
然后你可以像这样执行和打印:
result = query.all()
for postsubscription, likes in result:
print(postsubscription, likes)
关于python - 在使用 SQLAlchemy 的组合查询中,如何计算自引用关系(符合特定条件)的数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57685154/