'Q: SQLAlchemy 1.4 (2.0) problem converting results from session.execute(statement).scalars().all() or session.execute(statement).all()

I have this table defined as follows

class Carrier(Base):
    __tablename__ = 'Carrier'
    __table_args__ = {'comment': 'Carrier Code List'}

    Id = Column(Integer, primary_key=True, comment='PK for carrier table')
    Code = Column(String(50), index=True, comment='code to use')
    Description = Column(String(255), comment='description of the code')

To query the table I use the following

with Session(self.sqlengine, future=True) as session:
        statement = select(Carrier)
        #result = session.execute(statement).all()
        result = session.execute(statement).scalars().all()

I can loop through the results as follows

 for row in result:
    print(row.Id, row.Code)

According to the documentation, the following should return

# list of tuples
result = session.execute(statement).all()

# list of first element of each row (i.e. User objects)
result = session.execute(statement).scalars().all()

This is where I am getting confused. I am not getting a list of tuples or the first element of each row. I am getting an address to the instance of the class. For example <Carrier object at 0x000001B30ACB1D00>

It would be nice if it actually returned a tuple or a class with properties as I defined it in the table class but it is not.

I have also failed in all my attempts to convert it to a class that would be useful.

If I should be doing some mapping or converting I have no idea how nor have I been able to find an example. I feel the documentation is not very good either at least for 1.4/2.0

I would appreciate some assistance I know I am missing a nuance on how to convert but I do not know how to proceed.



Solution 1:[1]

For this setup

with sa.orm.Session(engine, future=True) as session:
    # create test data
    session.add_all([Carrier(Code="Alfa"), Carrier(Code="Bravo")])
    session.commit()
    
    # define our select statement
    statement = sa.select(Carrier)
    
    results = session.execute(statement).all()
    print(results)
    # [(<Carrier(Id=1, Code='Alfa')>,), (<Carrier(Id=2, Code='Bravo')>,)]

version 1.4 returns a list of Row objects. They are tuple-like and are represented in the same way as a tuple, surrounded with round brackets: (<Carrier(Id=1, Code='Alfa')>,).

Using .scalars()

    results = session.scalars(statement).all()
    print(results)
    # [<Carrier(Id=1, Code='Alfa')>, <Carrier(Id=2, Code='Bravo')>]

returns a list of "plain" ("scalar") Carrier objects. Notice that they are not enclosed in ( …,). The .scalars() call "looks inside" each Row object and returns the first element it finds (by default, index=0).

The difference is easier to see with simple scalar values:

    statement = sa.select(Carrier.Id)  # just the .Id column
    
    results = session.execute(statement).all()
    print(results)
    # [(1,), (2,)]
    
    results = session.scalars(statement).all()
    print(results)
    # [1, 2]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1