2

假设我有这样的一对多关系:

class Book(Base):
    __tablename__ = "books"
    id = Column(Integer)
    ...
    library_id = Column(Integer, ForeignKey("libraries.id"))

class Library(Base):
    __tablename__ = "books"
    id = Column(Integer)
    ...
    books = relationship(Book, backref="library")

现在,如果我有一本书的 ID,有没有办法从Library.books关系中检索它,“在这个特定的图书馆给我一本 id=10 的书”?就像是:

try:
    the_book = some_library.books.by_primary_key(10) 
except SomeException:
    print "The book with id 10 is not found in this particular library"

我能想到的解决方法(但我宁愿避免使用):

book = session.query(Book).get(10)
if book and book.library_id != library_id:
    raise SomeException("The book with id 10 is not found in this particular library")

或者

book = session.query(Book).filter(Book.id==10).filter(Book.library_id=library.id).one()

原因:想象有几种不同的关系(scifi_booksbooks_on_loan)指定不同的主要连接条件——手动查询需要为所有这些条件编写单独的查询,而 SQLAlchemy已经知道如何检索该关系的项目。此外,我更愿意一次加载所有书籍(通过访问 library.books)而不是发出单独的查询。

另一种可行但效率低下且不优雅的选择是:

for b in library.books:
    if b.id == book_id:
        return b

我目前使用的是:

library_books = {b.id:b for b in library.books}
for data in list_of_dicts_containing_book_id:
    if data['id'] in library_books:
        library_books[data['id']].do_something(data)
    else:
        print "Book %s is not in the library" % data['id']

我只是希望有一种更好的内置方法可以通过他们的 id 从关系中快速检索项目

UPD:我在sqlalchemy 邮件列表中提出了这个问题。

4

2 回答 2

4

SQLAlchemy 的查询对象的with_parent方法正是这样做的:

with_parent(实例,属性=无)

添加过滤条件,将给定实例与子对象或集合相关联,使用其属性状态以及已建立的 relationship() 配置。

所以在我的例子中,代码看起来像

q = session.query(Book)
q = q.with_parent(my_library, "scifi_books")
q = q.filter(Book.id==10).one()

即使my_library.scifi_books关系已经加载,这也会发出单独的查询。似乎没有“内置”方法可以通过其 PK 从已加载的关系中检索项目,因此最简单的方法是将关系转换为 dict 并使用它来查找项目:

book_lookup = {b.id: b for b in my_library.scifi_books}
book = books_lookup[10]
于 2012-11-14T02:33:29.683 回答
3

请参阅有关使用连接查询的SQLAlchemy 文档。所以你想要这样的东西(注意这是未经测试的):

query(Book, Library). \
    filter(Book.id==10). \
    filter(Book.library.id==needed_library_id).all()

如果Book -> Library引用是标量,您可以使用has()

query.filter(Library.books.has(id=10))

要一次对多本书进行批量查询,您可以使用in_()运算符:

query(Library).join('books', Book).filter(Book.id.in_([1, 2, 10])).all()
于 2012-08-20T04:49:00.687 回答