{"id":13424599,"url":"https://github.com/dialoguemd/fastapi-sqla","last_synced_at":"2025-05-15T13:08:17.392Z","repository":{"id":42123521,"uuid":"298082175","full_name":"dialoguemd/fastapi-sqla","owner":"dialoguemd","description":"SQLAlchemy extension for FastAPI with support for pagination, asyncio, SQLModel and pytest, ready for production.","archived":false,"fork":false,"pushed_at":"2025-05-13T15:19:02.000Z","size":1186,"stargazers_count":277,"open_issues_count":8,"forks_count":17,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-05-13T16:37:42.915Z","etag":null,"topics":["fastapi","fastapi-sqla","fastapi-sqlalchemy","library","sqlalchemy"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dialoguemd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-23T20:07:18.000Z","updated_at":"2025-05-13T03:29:01.000Z","dependencies_parsed_at":"2022-09-19T05:10:12.975Z","dependency_job_id":"d4dda2a0-ef02-43e2-884a-304e6388f4ec","html_url":"https://github.com/dialoguemd/fastapi-sqla","commit_stats":{"total_commits":115,"total_committers":7,"mean_commits":"16.428571428571427","dds":0.4,"last_synced_commit":"253d840aef6b3cc3bcdb235e0f00b038d9a4dbe1"},"previous_names":[],"tags_count":65,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dialoguemd%2Ffastapi-sqla","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dialoguemd%2Ffastapi-sqla/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dialoguemd%2Ffastapi-sqla/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dialoguemd%2Ffastapi-sqla/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dialoguemd","download_url":"https://codeload.github.com/dialoguemd/fastapi-sqla/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254346624,"owners_count":22055808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","fastapi-sqla","fastapi-sqlalchemy","library","sqlalchemy"],"created_at":"2024-07-31T00:00:56.831Z","updated_at":"2025-05-15T13:08:12.381Z","avatar_url":"https://github.com/dialoguemd.png","language":"Python","funding_links":[],"categories":["Third-Party Extensions"],"sub_categories":["Databases"],"readme":"# Fastapi-SQLA\n\n[![codecov](https://codecov.io/gh/dialoguemd/fastapi-sqla/branch/master/graph/badge.svg?token=BQHLryClIn)](https://codecov.io/gh/dialoguemd/fastapi-sqla)\n[![CircleCI](https://dl.circleci.com/status-badge/img/gh/dialoguemd/fastapi-sqla/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/dialoguemd/fastapi-sqla/tree/master)\n![PyPI](https://img.shields.io/pypi/v/fastapi-sqla)\n[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-brightgreen.svg)](https://conventionalcommits.org)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n\n\nFastapi-SQLA is an [SQLAlchemy] extension for [FastAPI] easy to setup with support for\npagination, asyncio, [SQLModel] and [pytest].\nIt supports SQLAlchemy\u003e=1.3 and is fully compliant with [SQLAlchemy 2.0].\nIt is developped, maintained and used on production by the team at [@dialoguemd] with\nlove from Montreal 🇨🇦.\n\n# Installing\n\nUsing [pip](https://pip.pypa.io/):\n```\npip install fastapi-sqla\n```\n\nNote that you need a [SQLAlchemy compatible engine](https://docs.sqlalchemy.org/en/20/core/engines.html) adapter. We test with `psycopg2` which you can install using the `psycopg2` extra.\n\n# Quick Example\n\nAssuming it runs against a DB with a table `user` with 3 columns, `id`, `name` and\nunique `email`:\n\n```python\n# main.py\nfrom contextlib import asynccontextmanager\nfrom fastapi import FastAPI, HTTPException\nfrom fastapi_sqla import Base, Item, Page, Paginate, Session, setup_middlewares, startup\nfrom pydantic import BaseModel, EmailStr\nfrom sqlalchemy import select\nfrom sqlalchemy.exc import IntegrityError\n\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    await startup()\n    yield\n\n\napp = FastAPI(lifespan=lifespan)\nsetup_middlewares(app)\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n\nclass UserIn(BaseModel):\n    name: str\n    email: EmailStr\n\n\nclass UserModel(UserIn):\n    id: int\n\n    class Config:\n        orm_mode = True\n\n\n@app.get(\"/users\", response_model=Page[UserModel])\ndef list_users(paginate: Paginate):\n    return paginate(select(User))\n\n\n@app.get(\"/users/{user_id}\", response_model=Item[UserModel])\ndef get_user(user_id: int, session: Session):\n    user = session.get(User, user_id)\n    if user is None:\n        raise HTTPException(404)\n    return {\"data\": user}\n\n\n@app.post(\"/users\", response_model=Item[UserModel])\ndef create_user(new_user: UserIn, session: Session):\n    user = User(**new_user.model_dump())\n    session.add(user)\n    try:\n        session.flush()\n    except IntegrityError:\n        raise HTTPException(409, \"Email is already taken.\")\n    return {\"data\": user}\n```\n\nCreating a db using `sqlite3`:\n```bash\nsqlite3 db.sqlite \u003c\u003cEOF\nCREATE TABLE user (\n    id    INTEGER PRIMARY KEY AUTOINCREMENT,\n    email TEXT NOT NULL,\n    name  TEXT NOT NULL\n);\nCREATE UNIQUE INDEX user_email_idx ON user (email);\nEOF\n```\n\nRunning the app:\n```bash\nsqlalchemy_url=sqlite:///db.sqlite?check_same_thread=false uvicorn main:app\n```\n\n# Configuration\n\n## Environment variables:\n\nThe keys of interest in `os.environ` are prefixed with `sqlalchemy_`.\nEach matching key (after the prefix is stripped) is treated as though it were the\ncorresponding keyword argument to [`sqlalchemy.create_engine`]\ncall.\n\nThe only required key is `sqlalchemy_url`, which provides the database URL, example:\n\n```bash\nexport sqlalchemy_url=postgresql://postgres@localhost\n```\n\n### Multi-session support\n\nIn order to configure multiple sessions for the application, \nset the environment variables with this prefix format: `fastapi_sqla__MY_KEY__`.\n\nAs with the default session, each matching key (after the prefix is stripped) \nis treated as though it were the corresponding keyword argument to [`sqlalchemy.create_engine`]\ncall.\n\nFor example, to configure a session with the `read_only` key:\n\n```bash\nexport fastapi_sqla__read_only__sqlalchemy_url=postgresql://postgres@localhost\n```\n\n### `asyncio` support using [`asyncpg`]\n\nSQLAlchemy `\u003e= 1.4` supports `asyncio`.\nTo enable `asyncio` support against a Postgres DB, install `asyncpg`:\n\n```bash\npip install asyncpg\n```\n\nAnd define the environment variable `sqlalchemy_url` with `postgres+asyncpg` scheme:\n\n```bash\nexport sqlalchemy_url=postgresql+asyncpg://postgres@localhost\n```\n\n## Setup the app AsyncContextManager (recommended):\n\n```python\nimport fastapi_sqla\nfrom fastapi import FastAPI\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    await fastapi_sqla.startup()\n    yield\n\n\napp = FastAPI(lifespan=lifespan)\nfastapi_sqla.setup_middlewares(app)\n```\n\n## Setup the app using startup/shutdown events (deprecated):\n\n```python\nimport fastapi_sqla\nfrom fastapi import FastAPI\n\napp = FastAPI()\nfastapi_sqla.setup(app)\n```\n\n# SQLAlchemy\n\n## Adding a new entity class:\n\n```python\nfrom fastapi_sqla import Base\n\n\nclass Entity(Base):\n    __tablename__ = \"table-name-in-db\"\n```\n\n## Getting an sqla session\n\n### Using dependency injection\n\nUse [FastAPI dependency injection] to get a session as a parameter of a path operation\nfunction.\n\nThe SQLAlchemy session is committed before the response is returned or rollbacked if any\nexception occurred:\n\n```python\nfrom fastapi import APIRouter\nfrom fastapi_sqla import AsyncSession, Session\n\nrouter = APIRouter()\n\n\n@router.get(\"/example\")\ndef example(session: Session):\n    return session.execute(\"SELECT now()\").scalar()\n\n\n@router.get(\"/async_example\")\nasync def async_example(session: AsyncSession):\n    return await session.scalar(\"SELECT now()\")\n```\n\nIn order to get a session configured with a custom key:\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import APIRouter, Depends\nfrom fastapi_sqla import (\n    AsyncSessionDependency,\n    SessionDependency,\n    SqlaAsyncSession,\n    SqlaSession,\n)\n\nrouter = APIRouter()\n\n\n# Preferred\n\nReadOnlySession = Annotated[SqlaSession, Depends(SessionDependency(key=\"read_only\"))]\nAsyncReadOnlySession = Annotated[\n    SqlaAsyncSession, Depends(AsyncSessionDependency(key=\"read_only\"))\n]\n\n@router.get(\"/example\")\ndef example(session: ReadOnlySession):\n    return session.execute(\"SELECT now()\").scalar()\n\n\n@router.get(\"/async_example\")\nasync def async_example(session: AsyncReadOnlySession):\n    return await session.scalar(\"SELECT now()\")\n\n\n# Alternative\n\n@router.get(\"/example/alt\")\ndef example_alt(session: SqlaSession = Depends(SessionDependency(key=\"read_only\"))):\n    return session.execute(\"SELECT now()\").scalar()\n\n\n@router.get(\"/async_example/alt\")\nasync def async_example_alt(\n    session: SqlaAsyncSession = Depends(AsyncSessionDependency(key=\"read_only\")),\n):\n    return await session.scalar(\"SELECT now()\")\n```\n\n### Using a context manager\n\nWhen needing a session outside of a path operation, like when using\n[FastAPI background tasks], use `fastapi_sqla.open_session` context manager.\nThe SQLAlchemy session is committed when exiting context or rollbacked if any exception\noccurred:\n\n```python\nfrom fastapi import APIRouter, BackgroundTasks\nfrom fastapi_sqla import open_async_session, open_session\n\nrouter = APIRouter()\n\n\n@router.get(\"/example\")\ndef example(bg: BackgroundTasks):\n    bg.add_task(run_bg)\n    bg.add_task(run_async_bg)\n\n\ndef run_bg():\n    with open_session() as session:\n        session.execute(\"SELECT now()\").scalar()\n\ndef run_bg_with_key():\n    with open_session(key=\"read_only\") as session:\n        session.execute(\"SELECT now()\").scalar()\n\nasync def run_async_bg():\n    async with open_async_session() as session:\n        await session.scalar(\"SELECT now()\")\n\nasync def run_async_bg_with_key():\n    async with open_async_session(key=\"read_only\") as session:\n        await session.scalar(\"SELECT now()\")\n```\n\n## Pagination\n\n```python\nfrom fastapi import APIRouter\nfrom fastapi_sqla import Base, Page, Paginate\nfrom pydantic import BaseModel\nfrom sqlalchemy import select\n\nrouter = APIRouter()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n\nclass UserModel(BaseModel):\n    id: int\n    name: str\n\n    class Config:\n        orm_mode = True\n\n\n@router.get(\"/users\", response_model=Page[UserModel])\ndef all_users(paginate: Paginate):\n    return paginate(select(User))\n```\n\nBy default:\n\n* It returns pages of 10 items, up to 100 items;\n* Total number of items in the collection is queried using [`Query.count`].\n* Response example for `/users?offset=40\u0026limit=10`:\n\n    ```json\n    {\n        \"data\": [\n            {\n                \"id\": 41,\n                \"name\": \"Pat Thomas\"\n            },\n            {\n                \"id\": 42,\n                \"name\": \"Mulatu Astatke\"\n            }\n        ],\n        \"meta\": {\n            \"offset\": 40,\n            \"total_items\": 42,\n            \"total_pages\": 5,\n            \"page_number\": 5\n        }\n    }\n    ```\n\n### Paginating non-scalar results\n\nTo paginate a query which doesn't return [scalars], specify `scalars=False` when invoking\n`paginate`:\n\n```python\nfrom fastapi import APIRouter\nfrom fastapi_sqla import Base, Page, Paginate\nfrom pydantic import BaseModel\nfrom sqlalchemy import func, select\nfrom sqlalchemy.orm import relationship\n\nrouter = APIRouter()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n    notes = relationship(\"Note\")\n\n\nclass Note(Base):\n    __tablename__ = \"note\"\n\n\nclass UserModel(BaseModel):\n    id: int\n    name: str\n    notes_count: int\n\n\n@router.get(\"/users\", response_model=Page[UserModel])\ndef all_users(paginate: Paginate):\n    query = (\n        select(User.id, User.name, func.count(Note.id).label(\"notes_count\"))\n        .join(Note)\n        .group_by(User)\n    )\n    return paginate(query, scalars=False)\n```\n\n\n### Customize pagination\n\nYou can customize:\n- Minimum and maximum number of items per pages;\n- How the total number of items in the collection is queried;\n\nTo customize pagination, create a dependency using `fastapi_sqla.Pagination`:\n\n```python\nfrom fastapi import APIRouter, Depends\nfrom fastapi_sqla import Base, Page, Pagination, Session\nfrom pydantic import BaseModel\nfrom sqlalchemy import func, select\n\nrouter = APIRouter()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n\nclass UserModel(BaseModel):\n    id: int\n    name: str\n\n\ndef query_count(session: Session) -\u003e int:\n    return session.execute(select(func.count()).select_from(User)).scalar()\n\n\nCustomPaginate = Pagination(min_page_size=5, max_page_size=500, query_count=query_count)\n\n\n@router.get(\"/users\", response_model=Page[UserModel])\ndef all_users(paginate: CustomPaginate = Depends()):\n    return paginate(select(User))\n```\n\n### Async pagination\n\nWhen using the asyncio support, use the `AsyncPaginate` dependency:\n\n```python\nfrom fastapi import APIRouter\nfrom fastapi_sqla import Base, Page, AsyncPaginate\nfrom pydantic import BaseModel\nfrom sqlalchemy import select\n\nrouter = APIRouter()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n\nclass UserModel(BaseModel):\n    id: int\n    name: str\n\n    class Config:\n        orm_mode = True\n\n\n@router.get(\"/users\", response_model=Page[UserModel])\nasync def all_users(paginate: AsyncPaginate):\n    return await paginate(select(User))\n```\n\nCustomize pagination by creating a dependency using `fastapi_sqla.AsyncPagination`:\n\n```python\nfrom fastapi import APIRouter, Depends\nfrom fastapi_sqla import Base, Page, AsyncPagination, AsyncSession\nfrom pydantic import BaseModel\nfrom sqlalchemy import func, select\n\nrouter = APIRouter()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n\nclass UserModel(BaseModel):\n    id: int\n    name: str\n\n\nasync def query_count(session: AsyncSession) -\u003e int:\n    result = await session.execute(select(func.count()).select_from(User))\n    return result.scalar()\n\n\nCustomPaginate = AsyncPagination(min_page_size=5, max_page_size=500, query_count=query_count)\n\n\n@router.get(\"/users\", response_model=Page[UserModel])\nasync def all_users(paginate: CustomPaginate = Depends()):\n    return await paginate(select(User))\n```\n\n### Multi-session support\n\nPagination supports multiple sessions as well. To paginate using a session \nconfigured with a custom key:\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import APIRouter, Depends\nfrom fastapi_sqla import (\n    AsyncPaginateSignature,\n    AsyncPagination,\n    Base,\n    Page,\n    PaginateSignature,\n    Pagination,\n)\nfrom pydantic import BaseModel\nfrom sqlalchemy import func, select\n\nrouter = APIRouter()\n\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n\nclass UserModel(BaseModel):\n    id: int\n    name: str\n\n\n# Preferred\n\nReadOnlyPaginate = Annotated[\n    PaginateSignature, Depends(Pagination(session_key=\"read_only\"))\n]\nAsyncReadOnlyPaginate = Annotated[\n    AsyncPaginateSignature, Depends(AsyncPagination(session_key=\"read_only\"))\n]\n\n@router.get(\"/users\", response_model=Page[UserModel])\ndef all_users(paginate: ReadOnlyPaginate):\n    return paginate(select(User))\n\n@router.get(\"/async_users\", response_model=Page[UserModel])\nasync def async_all_users(paginate: AsyncReadOnlyPaginate):\n    return await paginate(select(User))\n\n\n# Alternative\n\n@router.get(\"/users/alt\", response_model=Page[UserModel])\ndef all_users_alt(\n    paginate: PaginateSignature = Depends(\n        Pagination(session_key=\"read_only\")\n    ),\n):\n    return paginate(select(User))\n\n@router.get(\"/async_users/alt\", response_model=Page[UserModel])\nasync def async_all_users_alt(\n    paginate: AsyncPaginateSignature = Depends(\n        AsyncPagination(session_key=\"read_only\")\n    ),\n):\n    return await paginate(select(User))\n```\n\n# SQLModel support 🎉\n\nIf your project uses [SQLModel], then `Session` dependency is an SQLModel session::\n\n```python\n    from http import HTTPStatus\n\n    from fastapi import FastAPI, HTTPException\n    from fastapi_sqla import Item, Page, Paginate, Session, setup\n    from sqlmodel import Field, SQLModel, select\n\n    class Hero(SQLModel, table=True):\n        id: int | None = Field(default=None, primary_key=True)\n        name: str\n        secret_name: str\n        age: int | None = None\n\n\n    app = FastAPI()\n    setup(app)\n\n    @app.get(\"/heros\", response_model=Page[Hero])\n    def list_hero(paginate: Paginate) -\u003e Page[Hero]:\n        return paginate(select(Hero))\n\n\n    @app.get(\"/heros/{hero_id}\", response_model=Item[Hero])\n    def get_hero(hero_id: int, session: Session) -\u003e Item[Hero]:\n        hero = session.get(Hero, hero_id)\n        if hero is None:\n            raise HTTPException(HTTPStatus.NOT_FOUND)\n        return {\"data\": hero}\n\n```\n\n# Pytest fixtures\n\nThis library provides a set of utility fixtures, through its PyTest plugin, which is\nautomatically installed with the library. Using the plugin requires the `pytest_plugin` extra.\n\nBy default, no records are actually written to the database when running tests.\nThere currently is no way to change this behaviour.\n\n## `sqla_modules`\n\nYou must define this fixture, in order for the plugin to reflect table metadata in your\nSQLAlchemy entities. It should just import all of the application's modules which contain\nSQLAlchemy models.\n\nExample:\n\n```python\n# tests/conftest.py\nfrom pytest import fixture\n\n\n@fixture\ndef sqla_modules():\n    from app import sqla  # noqa\n```\n\n## `db_url`\n\nThe DB url to use.\n\nWhen `CI` key is set in environment variables, it defaults to using `postgres` as the\nhost name:\n\n```\npostgresql://postgres@postgres/postgres\n```\n\nIn other cases, the host is set to `localhost`:\n\n```\npostgresql://postgres@localhost/postgres\n```\n\nOf course, you can override it by overloading the fixture:\n\n```python\nfrom pytest import fixture\n\n\n@fixture(scope=\"session\")\ndef db_url():\n    return \"postgresql://postgres@localhost/test_database\"\n```\n\n## `async_sqlalchemy_url`\n\nDB url to use when using `asyncio` support. Defaults to `db_url` fixture with\n`postgresql+asyncpg://` scheme.\n\n\n## `session` \u0026 `async_session`\n\nSqla sessions to create db fixture:\n* All changes done at test setup or during the test are rollbacked at test tear down;\n* No record will actually be written in the database;\n* Changes in one regular session need to be committed to be available from other regular\n  sessions;\n* Changes in one async session need to be committed to be available from other async\n  sessions;\n* Changes from regular sessions are not available from `async` session and vice-versa\n  even when committed;\n\nExample:\n```python\nfrom pytest import fixture\n\n\n@fixture\ndef patient(session):\n    from er.sqla import Patient\n    patient = Patient(first_name=\"Bob\", last_name=\"David\")\n    session.add(patient)\n    session.commit()\n    return patient\n\n\n@fixture\nasync def doctor(async_session):\n    from er.sqla import Doctor\n    doctor = Doctor(name=\"who\")\n    async_session.add(doctor)\n    await async_session.commit()\n    return doctor\n```\n\n## `db_migration`\n\nA session scope fixture that runs `alembic upgrade` at test session setup and\n`alembic downgrade` at tear down.\n\nIt depends on `alembic_ini_path` fixture to get the path of `alembic.ini` file.\n\nTo use in a test or test module:\n\n```python\nfrom pytest import mark\n\npytestmark = mark.usefixtures(\"db_migration\")\n```\n\nTo use globally, add to [pytest options]:\n\n ```ini\n [pytest]\n usefixtures =\n     db_migration\n ```\n\nOr depends on it in top-level `conftest.py` and mark it as _auto-used_:\n\n```python\nfrom pytest import fixture\n\n\n@fixture(scope=\"session\", autouse=True)\ndef db_migration(db_migration):\n    pass\n```\n\n## `alembic_ini_path`\n\nIt returns the path of  `alembic.ini` configuration file. By default, it returns\n`./alembic.ini`.\n\n\n# Development\n\n## Prerequisites\n\n- **Python \u003e=3.9**\n- [**Poetry**](https://poetry.eustace.io/) to install package dependencies.\n- A postgres DB reachable at `postgresql://postgres@localhost/postgres`\n\n\n## Setup\n\n```bash\n$ poetry install --all-extras\n```\n\n## Running tests\n\n```bash\n$ poetry run pytest\n```\n\n#### Runing tests on multiple environments\n\n```bash\n$ poetry run tox\n```\n\n[`sqlalchemy.create_engine`]: https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.create_engine\n[`Query.count`]: https://docs.sqlalchemy.org/en/20/orm/queryguide/query.html#sqlalchemy.orm.Query.count\n[pytest options]: https://docs.pytest.org/en/stable/reference.html#confval-usefixtures\n[FastAPI]: https://fastapi.tiangolo.com/\n[FastAPI dependency injection]: https://fastapi.tiangolo.com/tutorial/dependencies/\n[FastAPI background tasks]: https://fastapi.tiangolo.com/tutorial/background-tasks/\n[SQLAlchemy]: http://sqlalchemy.org/\n[SQLAlchemy 2.0]: https://docs.sqlalchemy.org/en/20/changelog/migration_20.html\n[SQLModel]: https://sqlmodel.tiangolo.com\n[`asyncpg`]: https://magicstack.github.io/asyncpg/current/\n[scalars]: https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.Result.scalars\n[alembic]: https://alembic.sqlalchemy.org/\n[pytest]: https://docs.pytest.org/\n[@dialoguemd]: https://github.com/dialoguemd\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdialoguemd%2Ffastapi-sqla","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdialoguemd%2Ffastapi-sqla","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdialoguemd%2Ffastapi-sqla/lists"}