Skip to content

SQLAlchemy: The Definitive Deep Dive

πŸ—οΈ SQLAlchemy: The Definitive Deep Dive

SQLAlchemy is the β€œSQL Toolkit and ORM” for Python. It provides the Core layer for SQL expressions and the ORM layer for mapping Python classes to database tables.


🟒 Phase 1: Foundations (Engine & Connection Pool)

1. The Engine & Dialects

The Engine manages the connection pool. The Dialect specifies how Python interacts with the database (PostgreSQL, SQLite, MySQL).

from sqlalchemy import create_engine

# Connection pooling enabled by default (5 connections)
engine = create_engine(
    "postgresql+psycopg2://user:pass@localhost/db",
    pool_size=10, 
    max_overflow=20
)

2. MetaData & Reflection

MetaData is a collection of Table objects. Reflection allows you to load table definitions from an existing database automatically.

from sqlalchemy import MetaData, Table

metadata = MetaData()
users = Table("users", metadata, autoload_with=engine)

🟑 Phase 2: Intermediate (The Modern ORM)

3. Declarative Mapping (SQLAlchemy 2.0+)

Modern SQLAlchemy uses Mapped and mapped_column for type-safe models.

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    email: Mapped[str | None] # Optional column

4. Relationships & Foreign Keys

Relationships allow you to navigate between tables using Python attributes.

from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship

class Post(Base):
    __tablename__ = "post"
    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
    
    # Back-reference relationship
    author: Mapped["User"] = relationship(back_populates="posts")

User.posts: Mapped[list["Post"]] = relationship(back_populates="author")

🟠 Phase 3: Expert (Performance & Logic)

5. Hybrid Attributes

Hybrid attributes are Python properties that work both in Python code and as part of a SQL query.

from sqlalchemy.ext.hybrid import hybrid_property

class Employee(Base):
    __tablename__ = "employee"
    id: Mapped[int] = mapped_column(primary_key=True)
    first_name: Mapped[str]
    last_name: Mapped[str]

    @hybrid_property
    def full_name(self):
        return f"{self.first_name} {self.last_name}"

6. Association Proxies

Avoid navigating deep relationships manually (e.g., user.posts[0].tags[0]). Use Association Proxies to create shortcuts.

from sqlalchemy.ext.associationproxy import association_proxy

class User(Base):
    # Proxy all tag names from all posts of this user
    post_tags = association_proxy("posts", "tags")

7. Advanced Relationship Loading

  • joinedload: Single SQL JOIN (Best for Many-to-One).
  • selectinload: Separate SQL query with IN (...) (Best for One-to-Many).
  • subqueryload: Separate subquery (Older, less preferred than selectinload).
from sqlalchemy.orm import selectinload

with Session(engine) as session:
    users = session.query(User).options(selectinload(User.posts)).all()

πŸ”΄ Phase 4: Senior Architect (Distributed Systems)

8. Async SQLAlchemy (SQLAlchemy 2.0+)

For modern web frameworks like FastAPI, using the Async engine is mandatory for high throughput.

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession

async_engine = create_async_engine("postgresql+asyncpg://...")

async def main():
    async with AsyncSession(async_engine) as session:
        # Async DB logic
        pass

9. Event Listeners (Hooks)

SQLAlchemy has a powerful event system to inject logic (e.g., Auditing, Logging, Auto-formatting) into the database lifecycle.

from sqlalchemy import event

@event.listens_for(User, "before_insert")
def receive_before_insert(mapper, connection, target):
    # Log the insertion
    print(f"Adding user: {target.name}")

10. Table Inheritance

Map a Python class hierarchy to one or more database tables.

  • Single Table Inheritance: All subclasses in one table.
  • Joined Table Inheritance: Subclasses in separate tables joined by ID.
class Manager(User):
    # Manager-specific data in the same or joined table
    pass