2014-02-21 96 views
1

我有以下情形:过滤关系

class Author(Base): 
    __tablename__ = 'author' 

    id = Column(Integer, primary_key = True) 
    name = Column(String) 

    books = relationship('Books', backref='author') 


class Book(Base): 
    __tablename__ = 'book' 

    id = Column(Integer, primary_key = True) 
    title = Column(String) 

我想要做的就是加载谁拥有包含SQL在 标题一本书的所有作者。即

authors = session.query(Author)\ 
       .join(Author.books)\ 
       .filter(Book.title.like('%SQL%')\ 
       .all() 

似乎很简单。

然后我想要做的是遍历作者,并显示他们的 书籍。我期望在访问作者[0] .books时,它将仅返回 其标题中具有“SQL”的书籍。不过,我收到了所有分配给该作者的书籍 。当我访问关系时,该过滤器应用于作者列表,但不适用于他们的作品列表 。

如何构建我的查询,以便在筛选关系时(即 书籍),当我访问该关系时,仍然应用筛选?

回答

2

请阅读Routing Explicit Joins/Statements into Eagerly Loaded Collections。然后使用contains_eager,你可以组织你的查询,并得到你想要的东西:

authors = (
     session.query(Author) 
     .join(Author.books) 
     .options(contains_eager(Author.books)) # tell SA that we load "all" books for Authors 
     .filter(Book.title.like('%SQL%')) 
    ).all() 

请注意,你实际上是在欺骗SQLAlchemy的,以为它已加载的Author.books所有的集合,因此你会知道false有关世界真实状态的信息。

1

总之,这是不可能的。 (如果是这样,一个Author实例将取决于它如何被质疑,这没有任何意义有不同的books属性。)

你可以做的反而是查询反向关系:

books = session.query(Book) \ 
       .filter(Book.title.like('%SQL%')) \ 
       .all() 

然后,您可以在每本书上访问.author以收集由同一作者撰写的书籍。