I have two tables. With Sqlalchemy, I map them to two classes:
class A(base):
...
id = Column(BigInteger, primary_key=True, autoincrement=True)
class B(base):
...
id = Column(BigInteger, primary_key=True, autoincrement=True)
a_id = Column(BigInteger, ForeignKey(A.id))
timestamp = Column(DateTime)
a = relationship(A, backref="b_s")
I can use A.b_s to get a collection of B objects whose foreign key are as same as the primary key of A. It’s very easy to use lazy load or eager load. But now I have a question. I don’t want to load all B objects. I only want to load the first N objects ordered by timestamp. That is to say, A.b_s only loads some of related B objects. How can I use Sqlalchemy to do it?
Thanks a lot!
What you want to achive will not work with relations (and this is not a SA limitation, rather the proper way to treat relations and take care of the referential integrity).
However a simple query (wrapped in a method) will do the trick just fine:
edit-1: achieve that by having only 1-2 SQL statements
Now, to achieve this in only 1-2 SQL statements is definitely possible.
First of all, one needs a way to get the identifiers of
Bfortop Nof eachA. For this we will use thesqlalchemy.sql.expression.overfunction to compose a subquery:Version-1:
Now, the first version will load
As, the second will loadBs. The function returns dictionary withAs as keys and list ofBs as values:Version-2: this will trick SQLAlchemy to think that the
TOP N Bsthat are loaded in single query with A is actuallyA.b_s. VERY DANGEROUS, but neat. Read the comments in code which explain the pieces:To summarize, the Version-2 is probably the most direct answer to your question. Use it at own risk, because here you are tricking SA big time and if you modify the relationship property in any way, you might experience “Kaboom!”