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"
}
}