Asynchronous Database Toolkit
The `databases` library provides asynchronous database support for Python, designed to work with `asyncio` and `await`. It supports PostgreSQL, MySQL, and SQLite, and integrates well with SQLAlchemy Core expression language. The current version is 0.9.0, and it has an active development cadence with regular updates.
Warnings
- breaking Version 0.9.0 dropped support for Python 3.7 and earlier versions. Additionally, it now officially supports SQLAlchemy 2.x, which might introduce compatibility issues if you are still using older SQLAlchemy 1.x versions.
- breaking In version 0.8.0, connection and transaction isolation was significantly improved. Database connections are now task-local and not inherited by child tasks. The `@db.transaction` decorator uses the calling task's connection, and new tasks use new connections unless explicitly provided.
- gotcha You must install the specific database driver package for your chosen database alongside `databases`. For example, `pip install databases asyncpg` for PostgreSQL, `pip install databases aiomysql` for MySQL, or `pip install databases aiosqlite` for SQLite. Installing just `databases` is not sufficient for database connectivity.
- gotcha Compatibility with SQLAlchemy 1.4.x has been a recurring issue across several `databases` versions, with specific pins and fixes (e.g., `0.6.2` pinned `<=1.4.41`, `0.7.0` supported `>=1.4.42,<1.5`). While `0.9.0` adds SQLAlchemy 2.x support, transitioning from older SQLAlchemy 1.x with `databases` can be complex.
Install
-
pip install databases -
pip install databases[postgresql] -
pip install databases[mysql] -
pip install databases[sqlite]
Imports
- Database
from databases import Database
- Record
from databases import Record
Quickstart
import asyncio
import os
from databases import Database
async def main():
# Use an in-memory SQLite database for a simple example.
# For a real application, use a proper URL like DATABASE_URL = 'postgresql://user:pass@host/db'
database = Database(os.environ.get('DATABASE_URL', 'sqlite:///./test.db'))
try:
await database.connect()
print("Database connected.")
# Create a table
query = """
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name VARCHAR(100)
);
"""
await database.execute(query=query)
print("Table 'users' created or already exists.")
# Insert data
query = "INSERT INTO users(name) VALUES (:name)"
await database.execute(query=query, values={"name": "Alice"})
print("Inserted 'Alice'.")
# Select data
query = "SELECT id, name FROM users"
rows = await database.fetch_all(query=query)
for row in rows:
print(f"User: {row['id']}, {row['name']}")
except Exception as e:
print(f"An error occurred: {e}")
finally:
await database.disconnect()
print("Database disconnected.")
if __name__ == "__main__":
asyncio.run(main())