sqlalchemy select joined table on AsyncSession

1.1k Views Asked by At

So, I'm implementing async functionality on fastAPI using sqlalchemy.ext.asyncio & asyncpg, my problem is that the result of my joined query statement is not eagerly loaded even though I specify to my SQLModel that, that table has __mapper_args__ = {"eager_defaults": True} and used the joinLoaded to the query.

this is my User class as SQLModel

class Users(SQLModel, table=True):
    __tablename__: str = "users"
    id: Optional[int] = Field(default=None, primary_key=True)
    email: str = Field(index=True, sa_column=Column('email', String, unique=True))
    password: str = Field(max_length=1024)
    username: str = Field(max_length=100, nullable=True, index=True)

    ...some other fields here...

    user_role: Optional[UserRoles] = Relationship(back_populates='user')
    user_detail: Optional[UserDetails] = Relationship(back_populates='user')

    __mapper_args__ = {"eager_defaults": True}

this is my UserRoles class as SQLModel

class UserRoles(SQLModel, table=True):
    __tablename__: str = "user_roles"
    id: Optional[int] = Field(default=None, primary_key=True)
    role: str

    ...some other fields here...

    user: List["Users"] = Relationship(back_populates='user_role')

this is my fastAPI endpoint implementing sqlalchemy.ext.asyncio

'''
Note:
@user_route.get("/get_all_with_role", response_model=List[UserWithRolesRead])
this will return 
response -> 0 -> Users field required (type=value_error.missing)
response -> 0 -> UserRoles field required (type=value_error.missing)
'''
@user_route.get("/get_all_with_role")
async def get_all_with_role(
    email=Depends(token_service.secure),
    session: AsyncSession = Depends(session_local),
    ):
    async with session as sess:
        query = (
            select(Users, UserRoles)
            .join(UserRoles)
            .options(joinedload(Users.user_role))
        )
        result = await sess.execute(query)
        result = result.scalars().first() # I selected only one for the sake of debugging

        print(type(result))  # returns <class 'src.models.users.Users'>
        print(result)
        return result

and the return of print(result) on my console terminal is:

password='qwe123' id=7 active=True created_date=datetime.datetime(2022, 4, 3, 14, 26, 10, 109696) 
locked_end_date=None email='[email protected]' username='admin' user_role_id=4 last_login_date=None 
user_role=UserRoles(id=4, created_date=datetime.datetime(2022, 2, 4, 0, 0), active=True, role='Admin')

as the printed result suggests the user_role has tuple values of UserRoles. But in return result in the last line of @user_route.get("/get_all_with_role") has the value of:

{
  "password": "qwe123",
  "id": 7,
  "active": true,
  "created_date": "2022-04-03T14:26:10.109696",
  "locked_end_date": null,
  "email": "[email protected]",
  "username": "admin",
  "user_role_id": 4,
  "last_login_date": null
}

to summarized, the sqlalchemy query statement is properly functioning since, I can get the desired result on my terminal. But then when I try to get the result from the endpoint the the user_role is missing.

[UPDATE]

The result in previous implementation without the async functionality to the endpoint is this:

# fastAPI endpoint not async
@user_route.get("/get_all_with_role")
async def get_all_with_role(email=Depends(token_service.secure)):
    _sess = db.session_local()
    with _sess as sess:
        query = select(Users, UserRoles).join(UserRoles)
        result = sess.exec(query)
        return result.first()


# Result
{
  "Users": {
    "password": "$2b$12$ubLo5CMeORXikXrl8gI58OexeUxgqM/HI57yk6briHi1nvmwqO8R.",
    "id": 9,
    "active": true,
    "created_date": "2022-04-05T11:53:13.875607",
    "locked_end_date": null,
    "email": "0admin",
    "username": "0admin",
    "user_role_id": 4,
    "last_login_date": null
  },
  "UserRoles": {
    "id": 4,
    "created_date": "2022-02-04T00:00:00",
    "active": true,
    "role": "Admin"
  }
}
0

There are 0 best solutions below