scalars() returning first column and leaves out all other columns

Question:

I have the following code that should get the last known action of users and insert it’s timestamp in the user object:

async def get_last_activity(users, db):
    user_ids = [user.id for user in users]

    event_query = select(func.max(EventModel.datetime), EventModel.user_id).
        where(EventModel.user_id.in_(user_ids)).
        group_by(EventModel.user_id)
    events = (await db.execute(event_query)).scalars()

    for event in events:
        print(event)
        for user in users:
            if event.user_id == user.id:
                user.last_activity = event.datetime
    return users


@router.get(
    '/manageable',
    response_model=Users,
)
async def get_manageable_users(
        db: Session = Depends(get_db)
):
    """ Returns a list of users that the current user can manage """

    # @TODO: get users based on authorization helper.
    users = (await db.execute(select(UserModel))).scalars().all()
    users = await get_last_activity(users, db)

    return [{
        'id': user.id,
        'name': user.name,
        'email': user.email,
        'last_activity': user.last_activity
    } for user in users]

This results in the following error:

File "./app/api/v1/users/read.py", line 26, in get_last_activity
if event.user_id == user.id:
AttributeError: 'datetime.datetime' object has no attribute 'user_id

Even though the column is being selected in the generated query:

api001_1  | 2021-08-11 09:19:16,514 INFO sqlalchemy.engine.Engine SELECT max(events.datetime) AS max_1, events.user_id
api001_1  | FROM events
api001_1  | WHERE events.user_id IN (%s, %s) GROUP BY events.user_id
api001_1  | 2021-08-11 09:19:16,515 INFO sqlalchemy.engine.Engine [generated in 0.00323s] (1, 2)
api001_1  | 2016-10-07 22:00:29   <---------- print(event)

Does anyone know why the user_id column is not showing up in the Event objects?

Update:
It’s scalars() that is causing the issue. Without it this is the output of print(event):
(datetime.datetime(2016, 10, 7, 22, 0, 29), 1)
After running scalars only the datetime is picked up
So scalars seems to completely disregard the last number which is the user_id. Why?

Asked By: Snackoverflow

||

Answers:

I was under the impression that scalars() was supposed to map the result to an object. Upon reading the docs more closely, it can only do this with one column. This (optional) parameter defaults to 0 (index of column) and hence only the datetime is picked up.
I’m not using .scalars() anymore and instead have to do row[0], row[1]

Answered By: Snackoverflow
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.