home / skills / codingheader / myskills / 0xdarkmatter-python-database-patterns

This skill provides python database patterns with SQLAlchemy 2.0 guidance, enabling efficient modeling, querying, async usage, and migrations for robust apps.

This is most likely a fork of the python-database-patterns skill from 0xdarkmatter
npx playbooks add skill codingheader/myskills --skill 0xdarkmatter-python-database-patterns

Review the files below or copy the command above to add this skill to your agents.

Files (7)
SKILL.md
4.7 KB
---
name: python-database-patterns
description: "SQLAlchemy and database patterns for Python. Triggers on: sqlalchemy, database, orm, migration, alembic, async database, connection pool, repository pattern, unit of work."
compatibility: "SQLAlchemy 2.0+, Python 3.10+. Async requires asyncpg (PostgreSQL) or aiosqlite."
allowed-tools: "Read Write Bash"
depends-on: [python-typing-patterns, python-async-patterns]
related-skills: [python-fastapi-patterns]
---

# Python Database Patterns

SQLAlchemy 2.0 and database best practices.

## SQLAlchemy 2.0 Basics

```python
from sqlalchemy import create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))
    email: Mapped[str] = mapped_column(String(255), unique=True)
    is_active: Mapped[bool] = mapped_column(default=True)

# Create engine and tables
engine = create_engine("postgresql://user:pass@localhost/db")
Base.metadata.create_all(engine)

# Query with 2.0 style
with Session(engine) as session:
    stmt = select(User).where(User.is_active == True)
    users = session.execute(stmt).scalars().all()
```

## Async SQLAlchemy

```python
from sqlalchemy.ext.asyncio import (
    AsyncSession,
    async_sessionmaker,
    create_async_engine,
)
from sqlalchemy import select

# Async engine
engine = create_async_engine(
    "postgresql+asyncpg://user:pass@localhost/db",
    echo=False,
    pool_size=5,
    max_overflow=10,
)

# Session factory
async_session = async_sessionmaker(engine, expire_on_commit=False)

# Usage
async with async_session() as session:
    result = await session.execute(select(User).where(User.id == 1))
    user = result.scalar_one_or_none()
```

## Model Relationships

```python
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, Mapped, mapped_column

class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]

    # One-to-many
    posts: Mapped[list["Post"]] = relationship(back_populates="author")

class Post(Base):
    __tablename__ = "posts"

    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str]
    author_id: Mapped[int] = mapped_column(ForeignKey("users.id"))

    # Many-to-one
    author: Mapped["User"] = relationship(back_populates="posts")
```

## Common Query Patterns

```python
from sqlalchemy import select, and_, or_, func

# Basic select
stmt = select(User).where(User.is_active == True)

# Multiple conditions
stmt = select(User).where(
    and_(
        User.is_active == True,
        User.age >= 18
    )
)

# OR conditions
stmt = select(User).where(
    or_(User.role == "admin", User.role == "moderator")
)

# Ordering and limiting
stmt = select(User).order_by(User.created_at.desc()).limit(10)

# Aggregates
stmt = select(func.count(User.id)).where(User.is_active == True)

# Joins
stmt = select(User, Post).join(Post, User.id == Post.author_id)

# Eager loading
from sqlalchemy.orm import selectinload
stmt = select(User).options(selectinload(User.posts))
```

## FastAPI Integration

```python
from fastapi import Depends, FastAPI
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Annotated

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        yield session

DB = Annotated[AsyncSession, Depends(get_db)]

@app.get("/users/{user_id}")
async def get_user(user_id: int, db: DB):
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404)
    return user
```

## Quick Reference

| Operation | SQLAlchemy 2.0 Style |
|-----------|---------------------|
| Select all | `select(User)` |
| Filter | `.where(User.id == 1)` |
| First | `.scalar_one_or_none()` |
| All | `.scalars().all()` |
| Count | `select(func.count(User.id))` |
| Join | `.join(Post)` |
| Eager load | `.options(selectinload(User.posts))` |

## Additional Resources

- `./references/sqlalchemy-async.md` - Async patterns, session management
- `./references/connection-pooling.md` - Pool configuration, health checks
- `./references/transactions.md` - Transaction patterns, isolation levels
- `./references/migrations.md` - Alembic setup, migration strategies

## Assets

- `./assets/alembic.ini.template` - Alembic configuration template

---

## See Also

**Prerequisites:**
- `python-typing-patterns` - Mapped types and annotations
- `python-async-patterns` - Async database sessions

**Related Skills:**
- `python-fastapi-patterns` - Dependency injection for DB sessions
- `python-pytest-patterns` - Database fixtures and testing

Overview

This skill covers SQLAlchemy 2.0 patterns and practical database architecture for Python applications. It focuses on declarative models, synchronous and asynchronous sessions, relationship mapping, common query idioms, and integration with frameworks like FastAPI. The intent is to help you apply repository and unit-of-work ideas, configure connection pools, and run migrations predictably.

How this skill works

I provide concise examples and patterns that show how to define DeclarativeBase models, map relationships, and run queries using the SQLAlchemy 2.0 style API. Both sync and async engines and session factories are demonstrated, with guidance for transaction handling, connection pool settings, and eager loading strategies. There are also integration snippets for FastAPI dependency injection and pointers to migration and pooling best practices.

When to use it

  • Building CRUD services with SQLAlchemy 2.0 in sync or async codebases
  • Implementing repository and unit-of-work layers for testable data access
  • Integrating DB sessions into FastAPI endpoints via dependency injection
  • Configuring connection pools and tuning engine options for production
  • Setting up Alembic migrations and safe upgrade workflows

Best practices

  • Use DeclarativeBase with mapped_column and typed Mapped annotations for clear models
  • Prefer async_sessionmaker and create_async_engine for async apps; set expire_on_commit=False to avoid stale objects
  • Keep transactions explicit: open a session, begin a transaction, commit or rollback, and close promptly
  • Eager-load relationships with selectinload when you need related collections to avoid N+1 queries
  • Centralize engine and session factory creation to simplify testing and lifecycle management

Example use cases

  • A FastAPI service that exposes user and post endpoints using async DB sessions injected per request
  • A background worker that uses connection pooling to process jobs concurrently against PostgreSQL
  • A monolith refactor that introduces repository and unit-of-work patterns to decouple domain logic from ORM calls
  • A test suite using session factories and transactional rollbacks to isolate database tests
  • An Alembic migration workflow template for evolving schemas safely across environments

FAQ

Should I use async or sync SQLAlchemy?

Choose async when your application is IO-bound and already uses async frameworks like FastAPI or asyncio-based workers; use sync for simpler, blocking services or compatibility with libraries that are not async.

How do I avoid N+1 queries with relationships?

Use eager loading options such as selectinload or joinedload on your select statements to fetch related collections or objects in a single query pattern.