Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 469
PapeK24 Avatar asked Jan 26 '18 17:01

PapeK24


People also ask

How do I SELECT a column in SQLAlchemy?

SQLAlchemy Core The already created students table is referred which contains 4 columns, namely, first_name, last_name, course, score. But we will be only selecting a specific column. In the example, we have referred to the first_name and last_name columns. Other columns can also be provided in the entities list.

How do I get column names in SQLAlchemy?

To access the column names we can use the method keys() on the result. It returns a list of column names. Since, we queried only three columns, we can view the same columns on the output as well.

What does all () do in SQLAlchemy?

all() method. The Query object, when asked to return full entities, will deduplicate entries based on primary key, meaning if the same primary key value would appear in the results more than once, only one object of that primary key would be present.

What does query all () return?

all() will return all records which match our query as a list of objects.


2 Answers

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.

like image 106
Martijn Pieters Avatar answered Oct 08 '22 23:10

Martijn Pieters


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] 
like image 36
Anand Tripathi Avatar answered Oct 08 '22 22:10

Anand Tripathi