Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter by joinloaded table in SqlAlchemy?

Lets say I got 2 models, Document and Person. Document got relationship to Person via "owner" property. Now:

session.query(Document)\
    .options(joinedload('owner'))\
    .filter(Person.is_deleted!=True)

Will double join table Person. One person table will be selected, and the doubled one will be filtered which is not exactly what I want cuz this way document rows will not be filtered.

What can I do to apply filter on joinloaded table/model ?

like image 459
koszikot Avatar asked Oct 17 '11 12:10

koszikot


People also ask

What is difference between filter and filter by in SQLAlchemy?

The second one, filter_by(), may be used only for filtering by something specifically stated - a string or some number value. So it's usable only for category filtering, not for expression filtering. On the other hand filter() allows using comparison expressions (==, <, >, etc.)

How do I join three tables in SQLAlchemy?

Use Query. join() to join multiple tables together in SQLAlchemy. Call session. query(tables) with session as a Session object and with tables as a sequence to tables to join.

What does SQLAlchemy all () return?

As the documentation says, all() returns the result of the query as a list.

What is Joinedload?

joined loading - available via lazy='joined' or the joinedload() option, this form of loading applies a JOIN to the given SELECT statement so that related rows are loaded in the same result set.


1 Answers

You are right, table Person will be used twice in the resulting SQL, but each of them serves different purpose:

  • one is to filter the the condition: filter(Person.is_deleted != True)
  • the other is to eager load the relationship: options(joinedload('owner'))

But the reason your query returns wrong results is because your filter condition is not complete. In order to make it produce the right results, you also need to JOIN the two models:

qry = (session.query(Document).
        join(Document.owner). # THIS IS IMPORTANT
        options(joinedload(Document.owner)).
        filter(Person.is_deleted != True)
        )

This will return correct rows, even though it will still have 2 references (JOINs) to Person table. The real solution to your query is that using contains_eager instead of joinedload:

qry = (session.query(Document).
        join(Document.owner). # THIS IS STILL IMPORTANT
        options(contains_eager(Document.owner)).
        filter(Person.is_deleted != True)
        )
like image 155
van Avatar answered Sep 17 '22 02:09

van