繁体   English   中英

过滤SQLAlchemy查询结果对象的一对多属性

[英]Filter SQLAlchemy query result object's one-to-many attribute

假设我有几个对象,有一对多的关系,就像

class Parent():
    //id, other cols, etc
    children = relationship("Child", backref="parent")

class Child():
    parent_id = Column(Integer, ForeignKey("parent.id")
    child_type = Column(Enum("a","b"))

现在,我想查询Parent对象,但让他们的子进程按child_type进行过滤,即类似

session.query(Parent).join(Parent.children).filter(Child.child_type == "a")

这只会返回所有子节点的Parent,基本上忽略了过滤器。 这个结果是否可能,或者我是否还要查询Child?

实际上,您的查询会添加连接和过滤器,但只返回Parent实例。 实际上, 只有那些至少有一个类型为a Childa Parent实例。
然后,当您访问每个父节点上的.children时,将发出一个新的SQL语句,并且将加载该父节点的所有子节点。 您可以在内存中再次应用过滤器,或创建自己的查询,而不是依赖关系导航(注释掉),如下所示:

# select *only* those parents who have at least one child of type "a"
parents = session.query(Parent).join(Parent.children).filter(Child.child_type == "a")
for p in parents:
    # 1. in-memory filter: now select only type "a" children for each parent
    children_a = [c for c in p.children if c.child_type == 'a']
    # 2. custom query: now select only type "a" children for each parent
    # children_a = session.query(Child).with_parent(p).filter(Child.child_type == "a")

    print("AAA", p)
    for c in children_a:
        print("AAA ..", c)

在一个查询中执行此操作的方法如下所示,但要小心,因为您有效地告诉sqlalchemy您为父母加载了所有子项。 您可以将此方法用于执行查询然后丢弃/回收会话的方案:

# select all parents, and eager-load children of type "a"
parents = (session.query(Parent)
        .join(Parent.children).filter(Child.child_type == "a")
        # make SA think we loaded all *parent.children* collection
        .options(contains_eager('children'))
        )

for p in parents:
    children_a = p.children # now *children* are *incorrectly* filtered
    print("BBB", p)
    for c in children_a:
        print("BBB ..", c)

您尝试在一个查询中获得两个答案。 你可以要求所有有孩子类型的父母,或者你可以要求所有类型的孩子。 在第一种情况下,如果需要相应的子项,则必须再次过滤子项,在第二种情况下,您可以简单地获取相应的父项。 但哪种方式是正确的,取决于进一步的问题,你试图解决。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM