Basics¶
Advanced Alchemy provides pre-configured base classes for SQLAlchemy models with common primary key strategies and audit fields.
Base Classes¶
Advanced Alchemy includes several declarative base classes. Each provides different primary key strategies:
Base Class |
Features |
|---|---|
|
BIGINT primary keys for tables |
|
BIGINT primary keys for tables, Automatic created_at/updated_at timestamps |
|
Primary keys using database IDENTITY feature instead of sequences |
|
Primary keys using database IDENTITY feature, Automatic created_at/updated_at timestamps |
|
UUID primary keys |
|
UUIDv6 primary keys |
|
UUIDv7 primary keys |
|
UUID primary keys, Automatic created_at/updated_at timestamps |
|
UUIDv6 primary keys, Automatic created_at/updated_at timestamps |
|
Time-sortable UUIDv7 primary keys, Automatic created_at/updated_at timestamps |
|
URL-friendly unique identifiers, Shorter than UUIDs, collision resistant |
|
URL-friendly IDs with audit timestamps, Combines Nanoid benefits with audit trails |
Basic Mixins¶
Advanced Alchemy provides mixins to enhance model functionality:
Mixin |
Features |
|---|---|
|
Adds URL-friendly slug field
|
|
Automatic created_at/updated_at timestamps
Tracks record modifications
updated_at refreshes during flush when any mapped column value changes, while preserving explicit timestamp overrides |
|
Adds BigInt primary key with sequence
|
|
Adds primary key using database IDENTITY feature
|
Simple Model Example¶
Creating a basic model with BigIntAuditBase:
import datetime
from typing import Optional
from advanced_alchemy.base import BigIntAuditBase
from sqlalchemy.orm import Mapped, mapped_column
class Post(BigIntAuditBase):
"""Blog post model with auto-incrementing ID and audit fields.
Attributes:
title: The post title
content: The post content
published: Publication status
published_at: Timestamp of publication
created_at: Timestamp of creation (from BigIntAuditBase)
updated_at: Timestamp of last update (from BigIntAuditBase)
"""
title: Mapped[str] = mapped_column(index=True)
content: Mapped[str]
published: Mapped[bool] = mapped_column(default=False)
published_at: Mapped[Optional[datetime.datetime]] = mapped_column(default=None)
import datetime
from advanced_alchemy.base import BigIntAuditBase
from sqlalchemy.orm import Mapped, mapped_column
class Post(BigIntAuditBase):
"""Blog post model with auto-incrementing ID and audit fields.
Attributes:
title: The post title
content: The post content
published: Publication status
published_at: Timestamp of publication
created_at: Timestamp of creation (from BigIntAuditBase)
updated_at: Timestamp of last update (from BigIntAuditBase)
"""
title: Mapped[str] = mapped_column(index=True)
content: Mapped[str]
published: Mapped[bool] = mapped_column(default=False)
published_at: Mapped[datetime.datetime | None] = mapped_column(default=None)
This model includes:
Auto-incrementing
idcolumn (BigInt primary key)created_attimestamp (set on creation)updated_attimestamp (refreshed on modification)Custom columns:
title,content,published,published_at
Implementation Patterns¶
UUID vs BigInt Primary Keys¶
Different primary key types have distinct characteristics:
BigInt Primary Keys
from advanced_alchemy.base import BigIntAuditBase
class User(BigIntAuditBase):
username: Mapped[str] = mapped_column(unique=True)
Characteristics:
Sequential integers (1, 2, 3, …)
Smaller index size compared to UUIDs
Database generates values via sequences
Predictable ordering
Visible in URLs (
/users/123)
UUID Primary Keys
from advanced_alchemy.base import UUIDAuditBase
class User(UUIDAuditBase):
username: Mapped[str] = mapped_column(unique=True)
Characteristics:
Random 128-bit identifiers
Generated client-side (Python)
Suitable for distributed systems
Non-sequential
Not guessable in URLs (
/users/550e8400-e29b-41d4-a716-446655440000)
UUIDv7 Primary Keys
from advanced_alchemy.base import UUIDv7AuditBase
class User(UUIDv7AuditBase):
username: Mapped[str] = mapped_column(unique=True)
Characteristics:
Time-ordered UUIDs
Timestamp embedded in first 48 bits
Combines benefits of sequential and random IDs
Better database index performance than UUIDv4
Sortable by creation time
NanoID Primary Keys
from advanced_alchemy.base import NanoIDAuditBase
class User(NanoIDAuditBase):
username: Mapped[str] = mapped_column(unique=True)
Characteristics:
URL-friendly strings (uses
A-Za-z0-9_-)Shorter than UUIDs (21 characters vs 36)
Collision resistant
Generated client-side
Requires
nanoidextra:pip install advanced-alchemy[nanoid]
Using Mixins¶
Mixins add functionality to models without inheritance from base classes:
from advanced_alchemy.base import UUIDBase
from advanced_alchemy.mixins import SlugKey, AuditColumns
from sqlalchemy.orm import Mapped, mapped_column
class Article(UUIDBase, SlugKey, AuditColumns):
"""Article with UUID primary key, slug, and audit fields."""
title: Mapped[str] = mapped_column(unique=True)
content: Mapped[str]
This model combines:
UUIDBase- UUID primary keySlugKey- Automatic slug fieldAuditColumns- created_at/updated_at timestamps
Technical Constraints¶
Audit Field Behavior¶
The AuditColumns mixin provides automatic timestamps:
# ✅ Correct - updated_at refreshes automatically
user = await repository.get_one(User.id == user_id)
user.email = "new@example.com"
await session.commit()
# user.updated_at is automatically updated
# ✅ Correct - explicit override is preserved
user.updated_at = specific_timestamp
await session.commit()
# user.updated_at retains the explicit value
The updated_at field refreshes during flush when any mapped column changes, but preserves explicitly set values.
Primary Key Generation¶
Primary key generation differs by type:
# BigInt - database generates via sequence
user = User(username="alice") # No id needed
session.add(user)
await session.flush()
# user.id is populated by database
# UUID - Python generates client-side
user = User(username="bob") # UUID generated automatically
# user.id is populated before flush
# NanoID - Python generates client-side
user = User(username="charlie") # NanoID generated automatically
# user.id is populated before flush
Next Steps¶
Once you have basic models, you can add relationships between them.
See Relationships for foreign keys and many-to-many patterns.