Async-SQLModel is an extension module of SQLModel,
making it compatible with asynchronous programming, especially useful when lazy-loading relational fields asynchronously.
It supports awaitable fields in SQLModel model, making access to other fields awaitable.
Available under the MIT License.
$ pip install async-sqlmodel
You could create a AsyncSQLModel model like this:
fromtypingimportOptionalfromsqlmodelimportFieldfromasync_sqlmodelimportAsyncSQLModelclassHero(AsyncSQLModel, table=True):
id: Optional[int] =Field(default=None, primary_key=True)
name: strAdding an AwaitableField yields an awaitable field for the field specified in the argument.
fromtypingimportOptional, AwaitablefromsqlmodelimportFieldfromasync_sqlmodelimportAsyncSQLModel, AwaitableFieldclassHero(AsyncSQLModel, table=True):
id: Optional[int] =Field(default=None, primary_key=True)
name: strawt_name: Awaitable[str] =AwaitableField(field="name")This allows fields which may be subject to lazy loading or deferred / unexpiry loading to be accessed like this:
hero=Hero(name="Rusty-Man")
async_session.add(hero)
awaitasync_session.commit()
# the fields of "hero" have expired.# Therefore, accessing them will raise MissingGreenlet errorprint(hero.name)
# E sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; # can't call await_only() here. Was IO attempted in an unexpected place? # (Background on this error at: https://sqlalche.me/e/20/xd2s) # it works!print(awaithero.awt_name) # Rusty-ManYou can use an AwaitableField with Relationship.
fromtypingimportOptionalfromcollections.abcimportAwaitablefromsqlmodelimportField, selectfromasync_sqlmodelimportAsyncSQLModel, AwaitableFieldclassTeam(AsyncSQLModel, table=True):
id: Optional[int] =Field(default=None, primary_key=True)
heroes: List["Hero"] =Relationship()
awt_heroes: Awaitable[List["Hero"]] =AwaitableField(field="heroes")
classHero(AsyncSQLModel, table=True):
id: Optional[int] =Field(default=None, primary_key=True)
team_id: Optional[int] =Field(default=None, foreign_key="team.id")
team: Optional[Team] =Relationship(back_populates="heroes")
awt_team: Awaitable[Optional[Team]] =AwaitableField(field="team")Using an AwaitableField with Relationship fields can resolve the issues encountered during lazy loading:
hero= (
awaitsession.exec(select(Hero).where(Hero.id==hero_rusty_man.id))
).one()
# loading lazy loading attribute will raise MissingGreenlet errorteam=hero.team# E sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; # can't call await_only() here. Was IO attempted in an unexpected place? # (Background on this error at: https://sqlalche.me/e/20/xd2s) # it works!team=awaithero.awt_team