2

次のような1対多の関係があるとします。

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()

理由:異なるprimaryjoin条件を指定するいくつかの異なる関係(など)があると想像してくださいscifi_books-books_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(instance、property = None)

属性の状態と確立された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 に答える