Reputation: 3857
I have a one-to-many relationship between two types of objects Message and URL. A relationship is defined in the class URL with a backref named "link" that points to Message. Is there a way to make a filter, while querying on Message, to find for example the Message that possesses less than n URLs ?
I've tried with:
session.query(Message).filter(len(Message.link) < n).all()
And with
from sqlalchemy import func
session.query(Message).filter(func.count(Message.link) < n).all()
Each of them is sending me back an error. The first one:
InstrumentedAttribute has no len()
The second:
DatabaseError: (DatabaseError) ORA-00934: group function is not allowed here
Thanks to Audrius Kažukauskas and after some fiddling I've managed to do the following query:
session.query(Message.message_id)\
.join(URL)
.group_by(Message.message_id)
.having(func.count(URL.url_id) <= n)
Which works fine (send back a KeyedTuple instead of a collection of Message but I can live with it).
Upvotes: 1
Views: 3552
Reputation: 13543
For this to work, you need to join Message
with URL
, group by all fields in Message
and do the filtering in HAVING
clause:
q = session.query(Message).\
join(URL).\
group_by(Message).\
having(func.count(URL.id) < n)
filter()
(which translates to WHERE
in SQL) is applied before grouping and aggregate functions, while having()
filters rows after the grouping is done.
Upvotes: 4