Query for list of attribute instead of tuples in SQLAlchemy

I'm querying for the ids of a model, and get a list of (int,) tuples back instead of a list of ids. Is there a way to query for the attribute directly?

result = session.query(MyModel.id).all()

I realize it's possible to do

results = [r for (r,) in results]

Is it possible for the query to return that form directly, instead of having to process it myself?


Solution 1:

When passing in ORM-instrumented descriptors such as a column, each result is a named tuple, even for just one column. You could use the column name in a list comprehension to 'flatten' the list (you can drop the .all() call, iteration retrieves the objects too):

result = [r.id for r in session.query(MyModel.id)]

or use the fact that it's a tuple when looping a for loop and unpack it to a single-element tuple of targets:

result = session.query(MyModel.id)
for id, in result:
    # do something with the id

The latter could also be used in a list comprehension:

[id for id, in session.query(MyModel.id)]

You don't really have any options to force the row results to be just the single id value.

Solution 2:

It's strange that SQLalchemy is not providing a proper solution. In sqlalchemy if select a member variable such as a column then each result is a named tuple as @Martijn said. I came to a solution for this using zip function of python

ZIP Method

Zip official docuementation

zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)] Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.

Coming to your example

result = session.query(MyModel.id).all()
result = zip(*result)[0]

Output:

[id1, id2, id3...]

How it will work it will flatten list of tuples given as argument if you pass the list like

[(key11, key21), (key12,key22)]

Zip will convert this list of tuples into

[(key11, key12), (key21, key22)]

In your case you want every Initial value of tupe that is of the MyModel so you can take the 0th tuple from the list.

Chain Method

from itertools import chain
result = session.query(MyModel.id).all()  # result [(id1,), (id2,), (id3,)]
result = list(chain(*result))

Output

[id1, id2, id3]

For loop

result = session.query(MyModel.id).all()  # result [(id1,), (id2,), (id3,)]
result = [id for id, in result]

Output

[id1, id2, id3]