78

I am working in a pyramid project and I've the table in SQLAlchemy in declarative syntax

"""models.py"""
class Projects(Base):
    __tablename__ = 'projects'
    __table_args__ = {'autoload': True}

I get the results by using

""""views.py"""
session = DBSession()
row_data = session.query(Projects).filter_by(id=1).one()

How can I get the column names from this result.

PS: I am unable to use this method since I am using the declarative syntax.

Sukumar
  • 3,502
  • 3
  • 26
  • 29

8 Answers8

82

You can do something similar to Foo Stack's answer without resorting to private fields by doing:

conn.execute(query).keys()
prolibertas
  • 937
  • 1
  • 6
  • 6
  • 1
    I know this is an old answer, but hoping someone knows: if the query is for more than one entity, how do you get unambiguous column names? For a query like `Query(DataClass1).join(DataClass2).add_entity(DataClass2)`, if `DataClass1` and `DataClass2` have fields with the same names, then `keys()` returns a list with duplicate entries. – Tom Aug 24 '20 at 15:20
76
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import (Column, Index, Date, DateTime, Numeric, BigInteger, String, ForeignKey, Boolean)

Base = declarative_base()

class Project(Base):
    """sqlalchemy ORM for my table."""
    __tablename__ = "table1"
    id = Column("id", BigIntegerID, primary_key=True, autoincrement=True)
    date = Column("date", Date, nullable=False)
    value = Column("value", Numeric(20, 8))
    ...
    ...

Then this will return the columns names ['id', 'date', 'value', ...]:

Project.__table__.columns.keys()

Or this

Project.metadata.tables['table1'].columns.keys()
Lydia
  • 2,377
  • 16
  • 13
  • 5
    Note that 'columns' is interchangeable with 'c', so for above Project.metadata.tables[Project.__tablename__].c.keys() would also work. As would Project.__table__.c.keys() – CubeBot88 Jun 20 '17 at 11:57
39

The difference is between ORM and non-ORM, not declarative, which is just a helper for the ORM.

Query has a method column_descriptions() that was added for this purpose::

http://www.sqlalchemy.org/docs/orm/query.html#sqlalchemy.orm.query.Query.column_descriptions

the example there seems like it has a typo, says q.columns but it should be q.column_descriptions (edit: just fixed it).

gabbar0x
  • 4,046
  • 5
  • 31
  • 51
zzzeek
  • 72,307
  • 23
  • 193
  • 185
  • 1
    Thanks for the answer! Unfortunately, this returns [{'aliased': False, 'expr': , 'type': , 'name': 'Projects'}] I am trying to use reflection so that I don't have to specify the column name and with this method I'll still have to specify the column names. Or am I missing something? – Sukumar Jun 27 '11 at 08:04
  • 37
    I think I found the solution. I was able to get the column list by using Projects.__table__.columns.keys() – Sukumar Jun 27 '11 at 08:58
  • 1
    I think this only works if you are specifying which columns you want back in the query (which means you already know the column names). What @Sukumar and I need is the columns for a query constructed like `q=sess.query(MyTableObject).all()` – medley56 Jan 23 '20 at 16:48
  • 1
    `column_descriptions` is an attribute, not a method. – wolfmanx Jul 15 '20 at 07:02
14

Just playing around, this syntax will give you all the columns (so to solve your problem, set query to look at one table/object only):

conn.execute(query)._metadata.keys
Foo Stack
  • 2,185
  • 7
  • 24
  • 25
11

Short answer is that I ended up with the following solution:

column_names = query.statement.columns.keys()

Why?

I had a similar use case where I need to know the explicit columns returned by a query (i.e., the query does not necessarily contain all columns of a table class). Since the table is also massive in size (millions of entries), prolibertas answer was not satisfying in terms of performance. Here a performance comparison on my table with 94 columns:

# First create a query with 100.000 entries
query = (
            session.query(myTable)
            .limit(100000)
        )

# Then get the column names .. 

column_names = session.execute(query).keys()
# ---> ~ 5.730 seconds

column_names = query.statement.columns.keys()
# ---> ~ 0.003 seconds
ToJo
  • 1,339
  • 1
  • 15
  • 26
7

This link shows how to get all the metadata you could ever need about a table, column and more.

SQLAlchemy Metadata

Many of the answers above are based on the info on this page. Suppose we have declared a table.

employees = Table('employees', metadata,
    Column('employee_id', Integer, primary_key=True),
    Column('employee_name', String(60), nullable=False),
    Column('employee_dept', Integer, ForeignKey("departments.department_id"))
)

Here are some examples of getting metadata about the table.

# access the column "EMPLOYEE_ID":
employees.columns.employee_id

# or just
employees.c.employee_id

# via string
employees.c['employee_id']

# iterate through all columns
for c in employees.c:
    print(c)

# get the table's primary key columns
for primary_key in employees.primary_key:
    print(primary_key)

# get the table's foreign key objects:
for fkey in employees.foreign_keys:
    print(fkey)

# access the table's MetaData:
employees.metadata

# access the table's bound Engine or Connection, if its MetaData is bound:
employees.bind

# access a column's name, type, nullable, primary key, foreign key
employees.c.employee_id.name
employees.c.employee_id.type
employees.c.employee_id.nullable
employees.c.employee_id.primary_key
employees.c.employee_dept.foreign_keys

# get the "key" of a column, which defaults to its name, but can
# be any user-defined string:
employees.c.employee_name.key

# access a column's table:
employees.c.employee_id.table is employees

# get the table related by a foreign key
list(employees.c.employee_dept.foreign_keys)[0].column.table
Mark Kortink
  • 1,770
  • 4
  • 21
  • 36
3

Just

>>> q[0].keys()

After

row_data = session.query(Projects).filter_by(id=1).one()

Example :

>>> q = session.query(users_user.phone,users_user.first_name).filter(users_user.phone=='79267548577').limit(1).all()
>>> columns_names = q[0].keys

Result :

>>> q[0].keys()
['phone', 'first_name']
>>> 
-1

Would like to extend @zzzeek's answer. Indeed Query has column_descriptions attribute but it's not available for all the methods.

Consider the following two queries:

1. query = session.query(Projects).filter_by(<filter_condition>)
2. query = session.query(Projects).all() <-- This query does not have column_descriptions.

So if you come across this situation where you need to use column_descriptions attribute but using ...query(...).all() then you can change it to ...query(...).filter_by() i.e. filter_by() without any filter condition.

Abu Shumon
  • 1,834
  • 22
  • 36