Skip to content

Commit 38f30b0

Browse files
authored
Merge pull request #8 from svalench/docs/db-connection-examples
docs(readme): DB connection examples for PostgreSQL, MySQL, MSSQL (all ORMs)
2 parents 368aa7d + 5fa1372 commit 38f30b0

1 file changed

Lines changed: 209 additions & 0 deletions

File tree

README.md

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,215 @@ pip install "fastapi-viewsets[test]" # pytest, httpx, coverage, etc.
4646

4747
For async SQLAlchemy you still need a driver such as `aiosqlite`, `asyncpg`, or `aiomysql` alongside your database URL.
4848

49+
## Database connection examples
50+
51+
`fastapi-viewsets` doesn't bundle DB drivers — you pick them per stack.
52+
The table below maps each ORM to the install command, the driver(s)
53+
you need, and the URL shape for **PostgreSQL**, **MySQL**, and
54+
**Microsoft SQL Server**.
55+
56+
| ORM | PostgreSQL | MySQL | MSSQL |
57+
| --- | --- | --- | --- |
58+
| **SQLAlchemy (sync)** | `psycopg[binary]` or `psycopg2-binary` | `pymysql` or `mysqlclient` | `pyodbc` + ODBC Driver 17/18 |
59+
| **SQLAlchemy (async)** | `asyncpg` | `aiomysql` or `asyncmy` | `aioodbc` + ODBC Driver 17/18 |
60+
| **Tortoise ORM** | `asyncpg` (built-in) | `aiomysql` (built-in) | Not supported by Tortoise |
61+
| **Peewee** | `psycopg2-binary` | `pymysql` or `mysqlclient` | Not supported by this adapter |
62+
63+
> The `SQLAlchemyAdapter` auto-converts a sync URL to its async
64+
> counterpart (`postgresql://``postgresql+asyncpg://`,
65+
> `mysql://``mysql+aiomysql://`, `sqlite:///`
66+
> `sqlite+aiosqlite:///`). For MSSQL you have to set the async URL
67+
> explicitly via `SQLALCHEMY_ASYNC_DATABASE_URL`. If the matching async
68+
> driver is not installed, `SQLAlchemyAdapter` falls back to sync-only
69+
> mode and `get_async_session()` raises a helpful `RuntimeError`
70+
> (since v1.2.1).
71+
72+
The library reads database configuration from environment variables
73+
(loaded via `python-dotenv` from `.env`). Pick the ORM with `ORM_TYPE`,
74+
then set the URL with `<ORM>_DATABASE_URL` (or the generic
75+
`DATABASE_URL`).
76+
77+
### SQLAlchemy (sync and async)
78+
79+
```bash
80+
# PostgreSQL
81+
pip install "fastapi-viewsets[sqlalchemy]" "psycopg[binary]" asyncpg
82+
83+
# MySQL
84+
pip install "fastapi-viewsets[sqlalchemy]" pymysql aiomysql
85+
86+
# MSSQL (needs Microsoft ODBC Driver 17 or 18 on the host)
87+
pip install "fastapi-viewsets[sqlalchemy]" pyodbc aioodbc
88+
```
89+
90+
Example `.env` (one block at a time):
91+
92+
```dotenv
93+
# --- PostgreSQL ---
94+
ORM_TYPE=sqlalchemy
95+
SQLALCHEMY_DATABASE_URL=postgresql+psycopg://user:pass@db.example.com:5432/app
96+
# Optional explicit async URL; otherwise auto-derived to postgresql+asyncpg://
97+
SQLALCHEMY_ASYNC_DATABASE_URL=postgresql+asyncpg://user:pass@db.example.com:5432/app
98+
99+
# --- MySQL ---
100+
ORM_TYPE=sqlalchemy
101+
SQLALCHEMY_DATABASE_URL=mysql+pymysql://user:pass@db.example.com:3306/app?charset=utf8mb4
102+
SQLALCHEMY_ASYNC_DATABASE_URL=mysql+aiomysql://user:pass@db.example.com:3306/app?charset=utf8mb4
103+
104+
# --- MSSQL ---
105+
ORM_TYPE=sqlalchemy
106+
# URL-encode the ODBC driver name ("+" instead of spaces).
107+
SQLALCHEMY_DATABASE_URL=mssql+pyodbc://user:pass@db.example.com:1433/app?driver=ODBC+Driver+18+for+SQL+Server&Encrypt=yes&TrustServerCertificate=no
108+
SQLALCHEMY_ASYNC_DATABASE_URL=mssql+aioodbc://user:pass@db.example.com:1433/app?driver=ODBC+Driver+18+for+SQL+Server&Encrypt=yes&TrustServerCertificate=no
109+
```
110+
111+
Use `BaseViewset` for sync code or `AsyncBaseViewset` for async code
112+
(see the [Async quickstart](#async-quickstart-sqlalchemy-2x--pydantic-v2)
113+
below).
114+
115+
### Tortoise ORM
116+
117+
Tortoise is async-only. The adapter takes a database URL plus a list
118+
of model modules to register on startup.
119+
120+
```bash
121+
# PostgreSQL
122+
pip install "fastapi-viewsets[tortoise]" # pulls in asyncpg
123+
124+
# MySQL
125+
pip install "fastapi-viewsets[tortoise]" aiomysql
126+
```
127+
128+
```dotenv
129+
# --- PostgreSQL ---
130+
ORM_TYPE=tortoise
131+
TORTOISE_DATABASE_URL=postgres://user:pass@db.example.com:5432/app
132+
TORTOISE_MODELS=["app.models"]
133+
TORTOISE_APP_LABEL=models
134+
135+
# --- MySQL ---
136+
ORM_TYPE=tortoise
137+
TORTOISE_DATABASE_URL=mysql://user:pass@db.example.com:3306/app
138+
TORTOISE_MODELS=["app.models"]
139+
TORTOISE_APP_LABEL=models
140+
```
141+
142+
```python
143+
from fastapi import FastAPI
144+
from tortoise import Tortoise
145+
146+
from fastapi_viewsets import AsyncBaseViewset
147+
from fastapi_viewsets.orm.factory import ORMFactory
148+
149+
app = FastAPI()
150+
adapter = ORMFactory.get_default_adapter() # built from the env vars above
151+
152+
153+
@app.on_event("startup")
154+
async def _init_tortoise() -> None:
155+
"""Open the Tortoise connection pool and create schema if needed.
156+
157+
The adapter also initializes Tortoise lazily on first DB call;
158+
doing it here gives you control over schema creation.
159+
"""
160+
await Tortoise.init(
161+
db_url=adapter.database_url,
162+
modules={adapter.app_label: adapter.models},
163+
)
164+
await Tortoise.generate_schemas(safe=True)
165+
166+
167+
@app.on_event("shutdown")
168+
async def _close_tortoise() -> None:
169+
"""Close the Tortoise connection pool."""
170+
await Tortoise.close_connections()
171+
172+
173+
# Define your Tortoise models in app/models.py and pass them to AsyncBaseViewset.
174+
# from app.models import Item
175+
# from app.schemas import ItemSchema
176+
# items = AsyncBaseViewset(
177+
# endpoint="/items",
178+
# model=Item,
179+
# response_model=ItemSchema,
180+
# db_session=adapter.get_async_session,
181+
# orm_adapter=adapter,
182+
# tags=["items"],
183+
# )
184+
# items.register(methods=["LIST", "GET", "POST", "PATCH", "DELETE"])
185+
# app.include_router(items)
186+
```
187+
188+
> **MSSQL is not supported by Tortoise ORM.** Use SQLAlchemy with
189+
> `aioodbc` for SQL Server.
190+
191+
### Peewee
192+
193+
Peewee is sync-only. The adapter parses the URL and instantiates the
194+
right `Database` class.
195+
196+
```bash
197+
# PostgreSQL
198+
pip install "fastapi-viewsets[peewee]" psycopg2-binary
199+
200+
# MySQL
201+
pip install "fastapi-viewsets[peewee]" pymysql
202+
```
203+
204+
```dotenv
205+
# --- PostgreSQL ---
206+
ORM_TYPE=peewee
207+
PEEWEE_DATABASE_URL=postgresql://user:pass@db.example.com:5432/app
208+
209+
# --- MySQL ---
210+
ORM_TYPE=peewee
211+
PEEWEE_DATABASE_URL=mysql://user:pass@db.example.com:3306/app
212+
```
213+
214+
```python
215+
from fastapi import FastAPI
216+
217+
from fastapi_viewsets import BaseViewset
218+
from fastapi_viewsets.orm.factory import ORMFactory
219+
220+
app = FastAPI()
221+
adapter = ORMFactory.get_default_adapter() # built from the env vars above
222+
223+
# from app.models import Item # peewee.Model subclass
224+
# from app.schemas import ItemSchema # Pydantic v2 schema
225+
# items = BaseViewset(
226+
# endpoint="/items",
227+
# model=Item,
228+
# response_model=ItemSchema,
229+
# db_session=adapter.get_session,
230+
# orm_adapter=adapter,
231+
# tags=["items"],
232+
# )
233+
# items.register(methods=["LIST", "GET", "POST", "PATCH", "DELETE"])
234+
# app.include_router(items)
235+
```
236+
237+
> **MSSQL is not supported by this Peewee adapter** (the URL parser
238+
> only handles `sqlite:///`, `postgresql://`, `postgres://`,
239+
> `mysql://`). For SQL Server, use SQLAlchemy.
240+
241+
### Building the adapter from code (no env vars)
242+
243+
When you don't want to rely on environment variables, instantiate the
244+
adapter directly and pass it to the viewset via `orm_adapter=`:
245+
246+
```python
247+
from fastapi_viewsets.orm.factory import ORMFactory
248+
249+
adapter = ORMFactory.create_adapter(
250+
"sqlalchemy",
251+
{
252+
"database_url": "postgresql+psycopg://user:pass@db.example.com:5432/app",
253+
"async_database_url": "postgresql+asyncpg://user:pass@db.example.com:5432/app",
254+
},
255+
)
256+
```
257+
49258
## Quickstart (SQLAlchemy, sync)
50259

51260
Save as `main.py` in an empty folder and run `python main.py` or `uvicorn main:app --reload`.

0 commit comments

Comments
 (0)