如何显式定义subqueryload_all中使用的查询?

时间:2013-10-01 04:40:40

标签: python postgresql sqlalchemy relationships

我正在大量使用subqueryload / subqueryload_all,而且我遇到了边缘情况,我倾向于非常明确地定义在子查询期间使用的查询。例如,我有一个情况,我有帖子和评论。我的查询看起来像这样:

posts_q = db.query(Post).options(subqueryload(Post.comments))

正如您所看到的,我正在加载每个帖子的评论。问题是我不想要所有帖子的评论,我还需要考虑一个已删除的字段,并且需要按创建时间降序排序。我观察到这一点的唯一方法是在帖子和评论之间添加relationship()声明选项。我宁愿不这样做,b / c这意味着在那之后无法在任何地方重复使用这种关系,因为我在应用程序中有其他地方可能不适用这些约束。

我想做的是明确定义subqueryload / subqueryload_all用于加载帖子评论的查询。我读到了DisjointedEagerLoading here,看起来我可以简单地定义一个接受基本查询的特殊函数,以及一个加载指定关系的查询。对于这种情况,这是一条很好的路线吗?有没有人遇到过这种边缘案件?

2 个答案:

答案 0 :(得分:2)

答案是您可以定义PostComment之间的多种关系:

class Post(...):
    active_comments = relationship(Comment,
         primary_join=and_(Comment.post_id==Post.post_id, Comment.deleted=False),
         order_by=Comment.created.desc())

然后你应该能够通过这种关系进行子查询:

posts_q = db.query(Post).options(subqueryload(Post.active_comments))

您仍然可以在其他位置使用现有的.comments关系。

答案 1 :(得分:1)

我也有这个问题,我花了一些时间才意识到这是一个设计问题。当你说Post.comments时,你会提到“这些是该帖子的所有评论”的关系。但是,现在您想要过滤它们。如果您现在在subqueryload的某处指定了该条件,那么您实际上只将一部分值加载到Post.comments。因此,将缺少价值观。基本上,您在模型中的数据表示错误。

这里的问题是如何处理这个,因为你显然需要这个值某处。我的方式是自己构建子查询,然后在那里指定特殊条件。这意味着你得到两个对象:帖子列表和评论列表。这不是一个很好的解决方案,但至少它没有以错误的方式显示数据。如果您出于某种原因访问Post.comments,则可以放心地假设它包含所有帖子。

但是还有改进的余地:您可能希望将此附加到您的班级,这样您就不会携带两个变量。简单的方法可能是定义第二种关系,例如published_comments指定额外参数。然后你也可以控制没有人写入它,例如与attribute events。在这些事件中,您可以处理允许操作的方式,而不是禁止操纵。唯一的问题可能是更新发生时,例如当您向Post.comments添加评论时,published_comments将不会自动更新,因为他们彼此不了解。再次,如果这是一个必需的功能,我会为此事件(但是上面那个丑陋的解决方案你也不会这样做。)

作为最后的混合解决方案,您可以采用第一种方法,然后将这些值分配给您的对象,例如Post.deleted_comments = deleted_comments

这里要记住的是,操作ORM所做的查询通常不是一个聪明的主意,因为这可能会导致以后出现问题。我已采用这种方法并操纵查询(使用contains_eager这很容易实现)但是它在某些方面产生了问题(虽然通常是有效的)所以我放弃了这种方法。