Skip to content

Commit b0081f5

Browse files
committed
added the asyc-tools document and modified the menu
1 parent a5fe1d1 commit b0081f5

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed

docs/advanced/async-tools.md

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# Using Asynchronous Tools with SQLModel
2+
3+
Before diving into the guide, it's essential to highlight a few points:
4+
5+
- **FastAPI**: While FastAPI is not strictly required for using asynchronous tools with SQLModel, we'll use it in this example to simplify the demonstration.
6+
7+
- **Database Support**: SQLite does not support asynchronous operations. To run this example, you'll need a SQL Database that supports async. Remember to change the Database URL according to your database setup. We will be using Postgres in this example.
8+
9+
In this guide, we'll walk through how to integrate asynchronous capabilities with SQLModel, making use of FastAPI and asyncpg with a PostgreSQL database. This will enable us to perform non-blocking database operations and benefit from better performance in web applications.
10+
11+
## Installation:
12+
13+
To run the example, you need to install some required packages. Use the following commands to do so:
14+
15+
```
16+
pip install sqlmodel asyncpg fastapi uvicorn
17+
```
18+
19+
## Required Libraries:
20+
21+
- **FastAPI**: A modern, asynchronous web framework.
22+
- **SQLModel**: An ORM based on SQLAlchemy and Pydantic for easier database interaction.
23+
- **asyncpg**: An asynchronous PostgreSQL driver.
24+
25+
## Final code
26+
```
27+
from contextlib import asynccontextmanager
28+
from typing import Optional
29+
30+
from fastapi import FastAPI
31+
from pydantic import BaseModel
32+
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
33+
from sqlalchemy.orm import sessionmaker
34+
from sqlmodel import Field, SQLModel
35+
36+
# Initialize FastAPI application
37+
app = FastAPI()
38+
39+
40+
# Define User model for SQLModel
41+
class User(SQLModel, table=True):
42+
id: Optional[int] = Field(default=None, primary_key=True)
43+
name: str
44+
age: int
45+
46+
47+
# Define UserCreate model for Pydantic validation
48+
# For id field to not show up on the OpenAPI spec
49+
class UserCreate(BaseModel):
50+
name: str
51+
age: int
52+
53+
54+
# Database connection string
55+
DATABASE_URL = "postgresql+asyncpg://postgres:postgres@localhost/sampledb"
56+
57+
# Create an asynchronous engine for the database
58+
engine = create_async_engine(
59+
DATABASE_URL,
60+
echo=True,
61+
future=True,
62+
pool_size=20,
63+
max_overflow=20,
64+
pool_recycle=3600,
65+
)
66+
67+
68+
# Ayschronous Context manager for handling database sessions
69+
@asynccontextmanager
70+
async def get_session() -> AsyncSession:
71+
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
72+
async with async_session() as session:
73+
yield session
74+
75+
76+
# Function to create a new user in the database
77+
async def create_user(user: User) -> User:
78+
async with get_session() as session:
79+
session.add(user)
80+
await session.commit()
81+
await session.refresh(user)
82+
return user
83+
84+
85+
# Event handler for startup event of FastAPI application
86+
@app.on_event("startup")
87+
async def on_startup():
88+
async with engine.begin() as conn:
89+
# For SQLModel, this will create the tables (but won't drop existing ones)
90+
await conn.run_sync(SQLModel.metadata.create_all)
91+
92+
93+
# Endpoint to create a new user
94+
@app.post("/users/", response_model=User)
95+
async def create_user_endpoint(user: UserCreate):
96+
db_user = User(**user.dict())
97+
result = await create_user(db_user)
98+
return result
99+
100+
101+
# Main entry point of the application
102+
if __name__ == "__main__":
103+
import uvicorn
104+
105+
uvicorn.run(app, host="0.0.0.0", port=8000)
106+
107+
108+
```
109+
110+
## Code Breakdown
111+
112+
### Import Necessary Libraries
113+
114+
```python
115+
from contextlib import asynccontextmanager
116+
from typing import Optional
117+
118+
from fastapi import FastAPI
119+
from pydantic import BaseModel
120+
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
121+
from sqlalchemy.orm import sessionmaker
122+
from sqlmodel import Field, SQLModel
123+
```
124+
125+
Here, we're importing the required libraries and modules for our example.
126+
127+
### Initialize FastAPI Application
128+
129+
```python
130+
app = FastAPI()
131+
```
132+
133+
We create an instance of the FastAPI application.
134+
135+
### Define SQLModel Table
136+
137+
```python
138+
class User(SQLModel, table=True):
139+
id: Optional[int] = Field(default=None, primary_key=True)
140+
name: str
141+
age: int
142+
```
143+
144+
Here, we're defining a `User` model with `SQLModel`. The `table=True` argument indicates that this class should represent a database table. We define fields `id`, `name`, and `age` with appropriate types.
145+
146+
### Define Pydantic Model
147+
148+
```python
149+
class UserCreate(BaseModel):
150+
name: str
151+
age: int
152+
```
153+
154+
The `UserCreate` class serves as a data validation model using Pydantic. This ensures we only accept valid data when creating a new user.
155+
156+
### Database Configuration
157+
158+
```python
159+
DATABASE_URL = "postgresql+asyncpg://postgres:postgres@localhost/sampledb"
160+
```
161+
162+
We set up the database connection string. We're using `asyncpg` with PostgreSQL for asynchronous operations.
163+
164+
### Create Asynchronous Engine
165+
166+
```python
167+
engine = create_async_engine(
168+
DATABASE_URL,
169+
echo=True,
170+
future=True,
171+
pool_size=20,
172+
max_overflow=20,
173+
pool_recycle=3600,
174+
)
175+
```
176+
177+
We create an asynchronous engine for our database. Here, we've specified various parameters, such as `pool_size`, which determines the number of connections to maintain in the pool.
178+
179+
### Asynchronous Context Manager for Database Sessions
180+
181+
```python
182+
@asynccontextmanager
183+
async def get_session() -> AsyncSession:
184+
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
185+
async with async_session() as session:
186+
yield session
187+
```
188+
189+
We define an asynchronous context manager that provides a way to get a database session. It initializes a session, yields control to the caller for the duration of the block, and then handles cleanup once the block is exited.
190+
191+
### User Creation Function
192+
193+
```python
194+
async def create_user(user: User) -> User:
195+
async with get_session() as session:
196+
session.add(user)
197+
await session.commit()
198+
await session.refresh(user)
199+
return user
200+
```
201+
202+
This function allows us to create a new user in the database. It makes use of the `get_session` context manager.
203+
204+
### FastAPI Startup Event
205+
206+
```python
207+
@app.on_event("startup")
208+
async def on_startup():
209+
async with engine.begin() as conn:
210+
await conn.run_sync(SQLModel.metadata.create_all)
211+
```
212+
213+
When the FastAPI application starts, this event handler ensures that the necessary tables (in this case, the `User` table) are created if they don't already exist.
214+
215+
### FastAPI Endpoint to Create a New User
216+
217+
```python
218+
@app.post("/users/", response_model=User)
219+
async def create_user_endpoint(user: UserCreate):
220+
db_user = User(**user.dict())
221+
result = await create_user(db_user)
222+
return result
223+
```
224+
225+
We define an endpoint that allows the creation of a new user. It takes in data validated against the `UserCreate` model, uses it to create a `User` object, and then stores this user in the database.
226+
227+
### Main Entry Point
228+
229+
```python
230+
if __name__ == "__main__":
231+
import uvicorn
232+
233+
uvicorn.run(app, host="0.0.0.0", port=8000)
234+
```
235+
236+
Finally, if this script is run directly, it starts up a Uvicorn server to serve our FastAPI application on `0.0.0.0` (all available network interfaces) at port `8000`.
237+
238+
## Conclusion
239+
240+
With the combination of FastAPI, SQLModel, and asynchronous database drivers like asyncpg, we can create highly performant web applications that handle database interactions efficiently. This example demonstrates the essentials of setting up asynchronous operations with SQLModel in the context of a FastAPI application.

mkdocs.yml

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ nav:
8585
- Advanced User Guide:
8686
- advanced/index.md
8787
- advanced/decimal.md
88+
- advanced/async-tools.md
8889
- alternatives.md
8990
- help.md
9091
- contributing.md

0 commit comments

Comments
 (0)