我只想获得结果,其中对于每个游戏类别而言,该类别都位于ID列表中,因此无法执行以下操作。 Game.categories是hybrid_property,可为我提供游戏的类别。
这是我正在执行的查询,希望获得我指定的ID列表中至少具有一个类别的所有游戏的列表。
<appSettings file="C:\Program Files\Common\ServicesPlatform.config">
<add key="someKey" value="someValue"/>
</appSettings>
我的models.py是这个。请注意,每个游戏的类别取决于用户定义类别的数量。
games = Game.query \
.filter([category.id for category in Game.categories].in_([1, 2, 3])) \
.paginate(page, current_app.config['POSTS_PER_PAGE'], False)
我收到此错误
class CategoryUpvote(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
class Game(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255), index=True, unique=True)
category_upvotes = db.relationship('CategoryUpvote', backref='category', lazy='dynamic', cascade="save-update, merge, delete")
def add_upvote(self, category, user):
if not self.is_upvoted(category, user):
upvote = CategoryUpvote(category_id=category.id, game_id=self.id, user_id=user.id)
db.session.add(upvote)
else:
upvote = self.category_upvotes.filter(CategoryUpvote.category_id == category.id, CategoryUpvote.user_id == user.id, CategoryUpvote.game_id == self.id).first()
db.session.delete(upvote)
def is_upvoted(self, category, user):
return self.category_upvotes.filter(CategoryUpvote.category_id == category.id, CategoryUpvote.user_id == user.id, CategoryUpvote.game_id == self.id).count() > 0
@hybrid_property
def categories(self):
return Category.query \
.filter(CategoryUpvote.game_id == self.id, CategoryUpvote.category_id == Category.id) \
.group_by(Category.id) \
.order_by(db.func.count(CategoryUpvote.game_id).desc()) \
.limit(5) \
.all()
如何以某种方式为游戏的每个类别运行过滤器?例如
'list' object has no attribute 'in_'
如果Game将每个类别都作为外键,我也可以这样做
.filter(Game.categories[0].in_([1, 2, 3]), Game.categories[1].in_([1, 2, 3]), Game.categories[2].in_([1, 2, 3])) \
如何使用hybrid_property做类似的事情?
答案 0 :(得分:3)
属性Game.categories
尽管表示为hybrid_property
,但在SQL上下文中不起作用。当用于在类级别创建SQL expression objects时,它仍然对数据库执行实际查询,而是返回Category
对象的列表。您的大多数错误都是由于这一事实造成的。
此外,它实际上在Game
和CategoryUpvote
之间执行联接(使用SQL-92之前的样式),从 all 游戏中返回5个投票最高的类别。如果返回Query
而不显示在列表中,它将使该属性在一般情况下更加有用:
class Game(db.Model):
@hybrid_property
def categories(self):
return Category.query \
.join(CategoryUpvote) \
.filter(CategoryUpvote.game_id == self.id) \
.group_by(Category.id) \
.order_by(db.func.count(CategoryUpvote.game_id).desc()) \
.limit(5)
然后您将使用{p>来访问Game
实例的类别列表
game.categories.all()
或直接直接对其进行迭代。通过hybrid属性返回查询,您现在可以使用它来生成相关的子查询。然后,您可以尝试根据ID列表过滤类别,以谓词“ id
所标识的游戏的给定ID和类别ID之差为空”,换句话说,所有给定ID为包含在游戏的前5个类别ID集中:
# A portable way to build a (derived) table of ids. Use VALUES
# instead, if supported.
ids = union(*[select([literal(i).label('id')]) for i in [1, 2, 3]])
Game.query.filter(~exists(
ids.select()
.except_(Game.categories
.correlate(Game)
.with_entities(Category.id)
.subquery()
.select())))
请注意
我只想获得结果,其中每个游戏类别的类别都在ID的列表中
和
这是我正在做的查询,希望获得我指定的ID列表中至少具有一个类别的所有游戏的列表
并非同一件事,尽管严格的解释(列表中的每个类别)将要求使用对称差异,但上面的示例是牢记前者的。
要获取后者,您可以使用谓词“ id
所标识的游戏的给定ID与类别ID之间的交集不为空”进行查询,因此您需要交换except_()
到intersect()
并删除exists()
前面的NOT运算符~
–因为如果某些内容不为空,则存在一行或多行。
答案 1 :(得分:1)
面临的问题是因为您试图使用生成器来运行查询
category.id.in_([1,2,3]) for category in Game.categories
举一个小例子。当您运行以下代码时,您将在列表中获得0到5的期望输出。
>>> print([a for a in range(5)])
[0, 1, 2, 3, 4]
现在,如果您确实删除了方括号,那么
>>> print(a for a in range(5))
<generator object <genexpr> at 0x102829f10>
您可以看到输出是一个生成器表达式。您的代码也是如此,因为您没有评估python会将其作为生成器对象发送
我没有sqlalchemy的经验,但是我觉得您正在尝试实现的目标可以做到这一点:
for category in Game.categories
result.append(category.id.in_([1, 2, 3]))
games = Game.query \
.filter(Game.id.in_(result)) \
.paginate(page, current_app.config['POSTS_PER_PAGE'], False)