A highly opinionated SQLAlchemy extension for FastAPI.
Project description
fastapi-sqla
A highly opinionated SQLAlchemy extension for FastAPI:
- Setup using environment variables to connect on DB;
fastapi_sqla.Base
a declarative base class to reflect DB tables at startup;fastapi_sqla.with_session
a dependency to get an sqla session;- Automated commit/rollback of sqla session at the end of request before returning response;
- Pagination utilities;
- Pytest fixtures to easy writing test;
Configuration
Environment variables:
The keys of interest in os.environ
are prefixed with sqlalchemy_
.
Each matching key (after the prefix is stripped) is treated as though it were the
corresponding keyword argument to sqlalchemy.create_engine
call.
The only required key is sqlalchemy_url
, which provides the database URL.
Setup the app:
import fastapi_sqla
from fastapi import FastAPI
app = FastAPI()
fastapi_sqla.setup(app)
SQLAlchemy
Adding a new entity class:
from fastapi_sqla import Base
class Entity(Base):
__tablename__ = "table-name-in-db"
Getting an sqla session
Using dependency injection
Use FastAPI dependency injection to get a session as a parameter of a path operation function. SQLAlchemy session is committed before response is returned or rollbacked if any exception occurred:
from fastapi import APIRouter, Depends
from fastapi_sqla import Session
router = APIRouter()
@router.get("/example")
def example(session: Session = Depends()):
return session.execute("SELECT now()").scalar()
Using a context manager
When needing a session outside of a path operation, like when using
FastAPI background tasks, use fastapi_sqla.open_session
context manager.
SQLAlchemy session is committed when exiting context or rollbacked if any exception
occurred:
from fastapi import APIRouter, BackgroundTasks
from fastapi_sqla import open_session
router = APIRouter()
@router.get("/example")
def example(bg: BackgroundTasks):
bg.add_task(run_bg)
def run_bg():
with open_session() as session:
session.execute("SELECT now()").scalar()
Pagination
from fastapi import APIRouter, Depends
from fastapi_sqla import Base, Page, Paginate
from pydantic import BaseModel
from sqlalchemy import select
router = APIRouter()
class User(Base):
__tablename__ = "user"
class UserModel(BaseModel):
id: int
name: str
@router.get("/users", response_model=Page[UserModel])
def all_users(paginate: Paginate = Depends()):
return paginate(select(User))
By default:
-
It returns pages of 10 items, up to 100 items;
-
Total number of items in the collection is queried using
Query.count
for legacy orm queries and the equivalent for 2.0 style queries. -
Response example for
/users?offset=40&limit=10
:{ "data": [ { "id": 41, "name": "Pat Thomas" }, { "id": 42, "name": "Mulatu Astatke" } ], "meta": { "offset": 40, "total_items": 42, "total_pages": 5, "page_number": 5 } }
Customize pagination
You can customize:
- Minimum and maximum number of items per pages;
- How the total number of items in the collection is queried;
To customize pagination, create a dependency using fastapi_sqla.Pagination
from fastapi import APIRouter, Depends
from fastapi_sqla import Base, Page, Pagination, Session
from pydantic import BaseModel
from sqlalchemy import func, select
from sqlalchemy.sql import Select
router = APIRouter()
class User(Base):
__tablename__ = "user"
class UserModel(BaseModel):
id: int
name: str
def query_count(session: Session, query: Select) -> int:
return session.execute(select(func.count()).select_from(User)).scalar()
Paginate = Pagination(min_page_size=5, max_page_size=500, query_count=query_count)
@router.get("/users", response_model=Page[UserModel])
def all_users(paginate: Paginate = Depends()):
return paginate(select(User))
Pytest fixtures
This library provides a set of utility fixtures, through its PyTest plugin, which is automatically installed with the library.
By default, no records are actually written to the database when running tests. There currently is no way to change this behaviour.
sqla_modules
You must define this fixture, in order for the plugin to reflect table metadata in your SQLAlchemy entities. It should just import all of the application's modules which contain SQLAlchemy models.
Example:
# tests/conftest.py
from pytest import fixture
@fixture
def sqla_modules():
from er import sqla # noqa
db_url
The DB url to use.
When CI
key is set in environment variables, it defaults to using postgres
as the
host name:
postgresql://postgres@posgres/postgres
In other cases, the host is set to localhost
:
postgresql://postgres@localhost/postgres
Of course, you can override it by overloading the fixture:
from pytest import fixture
@fixture(scope="session")
def db_url():
return "postgresql://postgres@localhost/test_database"
session
Sqla session to create db fixture:
- All changes done at test setup or during the test are rollbacked at test tear down;
- No record will actually be written in the database;
- Changes in one session need to be committed to be available from other sessions;
Example:
from pytest import fixture
@fixture
def patient(session):
from er.sqla import Patient
patient = Patient(first_name="Bob", last_name="David")
session.add(patient)
session.commit()
return patient
db_migration
A session scope fixture that runs alembic upgrade
at test session setup and
alembic downgrade
at tear down.
It depends on alembic_ini_path
fixture to get the path of alembic.ini
file.
To use in a test or test module:
from pytest import mark
pytestmark = mark.usefixtures("db_migration")
To use globally, add to pytest options:
[pytest]
usefixtures =
db_migration
Or depends on it in top-level conftest.py
and mark it as auto-used:
from pytest import fixture
@fixture(scope="session", autouse=True)
def db_migration(db_migration):
pass
alembic_ini_path
It returns the path of alembic.ini
configuration file. By default, it returns
./alembic.ini
.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file fastapi-sqla-1.2.0.tar.gz
.
File metadata
- Download URL: fastapi-sqla-1.2.0.tar.gz
- Upload date:
- Size: 12.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.5 CPython/3.9.4 Linux/4.15.0-1092-aws
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 947f21e177f9cd3d907a9e99b388e75fa577a9f697ca566450972cfcf43201ef |
|
MD5 | 6b6dcaa0c3076ecd0457bf09fdbbc8fc |
|
BLAKE2b-256 | 796a157e62ddc7087d6c5a5f6035012cda91daf43b40f1d3b48685e6777f2108 |
File details
Details for the file fastapi_sqla-1.2.0-py3-none-any.whl
.
File metadata
- Download URL: fastapi_sqla-1.2.0-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.5 CPython/3.9.4 Linux/4.15.0-1092-aws
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 26cff9d8be68a092a2e15a22923d0b7886731a9963c119ef6733e48aa2d1a473 |
|
MD5 | b50da0c63592fde32a15131714cb3e96 |
|
BLAKE2b-256 | 8598de9119ea6d601a4ff4258e8cb4b12e8db816cb9418d31a63d01256eb17bd |