在 SQLAlchemy 中注释 `exists` 子查询
Annotate an `exists` subquery in SQLAlchemy
我有一个简单的新闻应用程序,用户可以在其中看到最新的 posts,他们可以喜欢其中的一些 posts。
模特:
from sqlalchemy.orm import relationship, backref
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
...
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
body = db.Column(db.String)
...
class Like(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.ForeignKey(User.id))
post_id = db.Column(db.ForeignKey(Post.id))
post = relationship(Post, backref=backref('likes'))
我想要实现的是让每个 post 都有一个附加字段,该字段指示登录用户是否喜欢 post,但以优化的方式进行每个 post.
的查询
我尝试这样做是模式级别,使用 marshmallow-sqlalchemy
:
from marshmallow import fields
from app import ma
from news.models import Post
class PostSchema(ma.ModelSchema):
is_liked = fields.Method("get_is_liked")
def get_is_liked(self, obj):
user = self.context['user']
return bool(Like.filter_by(user_id=user.id, post_id=obj.id).first())
class Meta:
model = Post
但这会导致每个 post.
的 N 个查询
我也试过像 Django ORM 中的注解那样实现这个:
class PostListView(Resource):
# I have the user object here using a decorator
def get(self, user):
# I know that this is a bad syntax
query = Post.query(Post.likes.filter_by(user_id=user.id).exists().label('is_liked')))
schema = PostSchema(strict=True, many=True, context={"user": user})
result = schema.dump(query.all())
return result.data
我也看到了这个,它在数据库级别做同样的事情,但我想用SQLAlchemy
。
提前致谢。
这行得通吗?这个想法是加载 posts 以便 Post.likes
只包含当前用户是喜欢 post 的用户的情况。 contains_eager('likes')
应该在 Post
.
中加载 likes
数组
# user_id is the id of the current user
q = session.query(Post) \
.outerjoin(Like, and_(Like.post_id == Post.id,
Like.user_id == user_id)) \
.options(contains_eager('likes'))
然后 is_liked
可能是 return len(self.likes) > 0
我有一个简单的新闻应用程序,用户可以在其中看到最新的 posts,他们可以喜欢其中的一些 posts。
模特:
from sqlalchemy.orm import relationship, backref
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
...
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
body = db.Column(db.String)
...
class Like(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.ForeignKey(User.id))
post_id = db.Column(db.ForeignKey(Post.id))
post = relationship(Post, backref=backref('likes'))
我想要实现的是让每个 post 都有一个附加字段,该字段指示登录用户是否喜欢 post,但以优化的方式进行每个 post.
的查询我尝试这样做是模式级别,使用 marshmallow-sqlalchemy
:
from marshmallow import fields
from app import ma
from news.models import Post
class PostSchema(ma.ModelSchema):
is_liked = fields.Method("get_is_liked")
def get_is_liked(self, obj):
user = self.context['user']
return bool(Like.filter_by(user_id=user.id, post_id=obj.id).first())
class Meta:
model = Post
但这会导致每个 post.
的 N 个查询我也试过像 Django ORM 中的注解那样实现这个:
class PostListView(Resource):
# I have the user object here using a decorator
def get(self, user):
# I know that this is a bad syntax
query = Post.query(Post.likes.filter_by(user_id=user.id).exists().label('is_liked')))
schema = PostSchema(strict=True, many=True, context={"user": user})
result = schema.dump(query.all())
return result.data
我也看到了这个SQLAlchemy
。
提前致谢。
这行得通吗?这个想法是加载 posts 以便 Post.likes
只包含当前用户是喜欢 post 的用户的情况。 contains_eager('likes')
应该在 Post
.
likes
数组
# user_id is the id of the current user
q = session.query(Post) \
.outerjoin(Like, and_(Like.post_id == Post.id,
Like.user_id == user_id)) \
.options(contains_eager('likes'))
然后 is_liked
可能是 return len(self.likes) > 0