Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I inspect a sqlalchemy query object to find the already joined tables?

I'm trying to programmatically build a search query, and to do so, I'm joining a table.

class User(db.Model):
    id = db.Column(db.Integer(), primary_key=True)

class Tag(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
    user_id = db.Column(db.Integer(), db.ForeignKey('user.id'))
    title = db.Column(db.String(128))
    description = db.Column(db.String(128))

This is a bit of a contrived example - I hope it makes sense.

Say my search function looks something like:

def search(title_arg, desc_arg):
    query = User.query
    if title_arg:
        query = query.join(Tag)
        query = query.filter(Tag.title.contains(title_arg))
    if desc_arg:
        query = query.join(Tag)
        query = query.filter(Tag.description.contains(desc_arg))

    return query

Previously, I’ve kept track of what tables that have already been joined in a list, and if the table is in the list, assume it’s already joined, and just add the filter.

It would be cool if I could look at the query object, see that Tag is already joined, and skip it if so. I have some more complex query building that would really benefit from this.

If there’s a completely different strategy for query building for searches that I’ve missed, that would be great too. Or, if the above code is fine if I join the table twice, that's great info as well. Any help is incredibly appreciated!!!

like image 772
Hoopes Avatar asked Mar 06 '16 16:03

Hoopes


2 Answers

You can find joined tables in query._join_entities

joined_tables = [mapper.class_ for mapper in query._join_entities]
like image 173
r-m-n Avatar answered Sep 18 '22 20:09

r-m-n


According to the r-m-n answer:

Some where in your initialization of your project, add a unique_join method to the sqlalchemy.orm.Query object like this:

def unique_join(self, *props, **kwargs):
    if props[0] in [c.entity for c in self._join_entities]:
        return self
    return self.join(*props, **kwargs)

Query.unique_join = unique_join

Now use query.unique_join instead of query.join:

query = query.unique_join(Tag)
like image 31
mtoloo Avatar answered Sep 17 '22 20:09

mtoloo