https://github.com/2jun0/async-sqlmodel
Async-SQLModel is an extension module of SQLModel, making it compatible with asynchronous programming, especially useful when lazy-loading relational fields asynchronously.
https://github.com/2jun0/async-sqlmodel
async awaitable python sqlmodel
Last synced: 12 days ago
JSON representation
Async-SQLModel is an extension module of SQLModel, making it compatible with asynchronous programming, especially useful when lazy-loading relational fields asynchronously.
- Host: GitHub
- URL: https://github.com/2jun0/async-sqlmodel
- Owner: 2jun0
- License: mit
- Created: 2024-03-27T09:35:58.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-04-01T19:06:50.000Z (about 2 years ago)
- Last Synced: 2024-04-02T19:25:42.996Z (about 2 years ago)
- Topics: async, awaitable, python, sqlmodel
- Language: Python
- Homepage:
- Size: 36.1 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## Async-SQLModel
Async-SQLModel is an extension module of [SQLModel](https://sqlmodel.tiangolo.com/),
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](./LICENSE).
## Installation
```
$ pip install async-sqlmodel
```
## Usage
### Create a AsyncSQLModel Model
You could create a **AsyncSQLModel** model like this:
```python
from typing import Optional
from sqlmodel import Field
from async_sqlmodel import AsyncSQLModel
class Hero(AsyncSQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
```
### Add an AwaitableField
Adding an **AwaitableField** yields an awaitable field for the `field` specified in the argument.
```python
from typing import Optional, Awaitable
from sqlmodel import Field
from async_sqlmodel import AsyncSQLModel, AwaitableField
class Hero(AsyncSQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
awt_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:
```python
hero = Hero(name="Rusty-Man")
async_session.add(hero)
await async_session.commit()
# the fields of "hero" have expired.
# Therefore, accessing them will raise MissingGreenlet error
print(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(await hero.awt_name) # Rusty-Man
```
### Use an AwaitableField with Relationship
You can use an **AwaitableField** with **Relationship**.
```python
from typing import Optional
from collections.abc import Awaitable
from sqlmodel import Field, select
from async_sqlmodel import AsyncSQLModel, AwaitableField
class Team(AsyncSQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
heroes: List["Hero"] = Relationship()
awt_heroes: Awaitable[List["Hero"]] = AwaitableField(field="heroes")
class Hero(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:
```python
hero = (
await session.exec(select(Hero).where(Hero.id == hero_rusty_man.id))
).one()
# loading lazy loading attribute will raise MissingGreenlet error
team = 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 = await hero.awt_team
```