SQLAlchemy building blocks for Belgie
Project description
belgie-alchemy
SQLAlchemy 2.0 utilities for Belgie.
Overview
belgie-alchemy provides the AlchemyAdapter and database settings for Belgie.
For SQLAlchemy building blocks (Base, mixins, types), use brussels:
- Base: Declarative base with dataclass mapping and sensible defaults
- Mixins:
PrimaryKeyMixin(UUID),TimestampMixin(created/updated/deleted timestamps) - Types:
DateTimeUTC(timezone-aware datetimes),Json(dialect-specific JSON storage)
The examples below use brussels directly so you can own your models.
Quick Start
from datetime import datetime
from brussels.base import DataclassBase
from brussels.mixins import PrimaryKeyMixin, TimestampMixin
from brussels.types import DateTimeUTC
from sqlalchemy.orm import Mapped, mapped_column
class Article(DataclassBase, PrimaryKeyMixin, TimestampMixin):
__tablename__ = "articles"
title: Mapped[str]
published_at: Mapped[datetime] = mapped_column(DateTimeUTC)
This gives you:
- UUID primary key with server-side generation
- Automatic
created_at,updated_at,deleted_attimestamps - Timezone-aware datetime handling
- Dataclass-style
__init__,__repr__,__eq__
Building Blocks
Base
Declarative base with dataclass mapping enabled:
from brussels.base import DataclassBase
from sqlalchemy.orm import Mapped, mapped_column
class MyModel(DataclassBase):
__tablename__ = "my_models"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
# Dataclass-style instantiation
model = MyModel(id=1, name="example")
Features:
- Consistent naming conventions for constraints
- Automatic type annotation mapping (
datetime→DateTimeUTC) - Dataclass mapping for convenient instantiation
Mixins
PrimaryKeyMixin
Adds a UUID primary key with server-side generation:
from brussels.base import DataclassBase
from brussels.mixins import PrimaryKeyMixin
class MyModel(DataclassBase, PrimaryKeyMixin):
__tablename__ = "my_models"
# Automatically includes: id: Mapped[UUID]
The id field:
- Type:
UUID - Server-generated using
gen_random_uuid() - Indexed and unique
- Primary key
TimestampMixin
Adds automatic timestamp tracking:
from brussels.base import DataclassBase
from brussels.mixins import TimestampMixin
class MyModel(DataclassBase, TimestampMixin):
__tablename__ = "my_models"
# Automatically includes:
# - created_at: Mapped[datetime]
# - updated_at: Mapped[datetime] (auto-updates on changes)
# - deleted_at: Mapped[datetime | None]
Features:
created_atset automatically on insertupdated_atauto-updates on row changesdeleted_atfor soft deletionmark_deleted()method to setdeleted_at
Types
DateTimeUTC
Timezone-aware datetime storage:
from datetime import datetime
from brussels.base import DataclassBase
from brussels.types import DateTimeUTC
from sqlalchemy.orm import Mapped, mapped_column
class Event(DataclassBase):
__tablename__ = "events"
id: Mapped[int] = mapped_column(primary_key=True)
happened_at: Mapped[datetime] = mapped_column(DateTimeUTC)
Features:
- Automatically converts naive datetimes to UTC
- Preserves timezone-aware datetimes
- Always returns UTC-aware datetimes from database
- Works with PostgreSQL, SQLite, MySQL
Json
Dialect-specific JSON storage (JSONB on PostgreSQL):
from brussels.base import DataclassBase
from brussels.types import Json
from sqlalchemy.orm import Mapped, mapped_column
class User(DataclassBase):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
# Store scopes as JSON (works everywhere)
scopes: Mapped[list[str] | None] = mapped_column(Json, default=None)
Features:
- PostgreSQL: Uses
JSONB - SQLite/MySQL: Uses
JSON
For PostgreSQL with application-specific enum types, you can override:
from enum import StrEnum
from brussels.base import DataclassBase
from sqlalchemy import ARRAY
from sqlalchemy.dialects.postgresql import ENUM
from sqlalchemy.orm import Mapped, mapped_column
class AppScope(StrEnum):
READ = "resource:read"
WRITE = "resource:write"
ADMIN = "admin"
class User(DataclassBase):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
# Option 2: PostgreSQL native ENUM array (type-safe)
scopes: Mapped[list[AppScope] | None] = mapped_column(
ARRAY(ENUM(AppScope, name="app_scope", create_type=True)),
default=None,
)
Complete Example: Auth Models
See examples/alchemy/auth_models.py for a complete reference implementation of authentication models:
User- with email, verification, and scopesAccount- OAuth provider linkageSession- user session managementOAuthState- OAuth flow state
These are templates - copy them to your project and customize as needed.
Example structure:
from datetime import datetime
from uuid import UUID
from brussels.base import DataclassBase
from brussels.mixins import PrimaryKeyMixin, TimestampMixin
from brussels.types import DateTimeUTC, Json
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
class User(DataclassBase, PrimaryKeyMixin, TimestampMixin):
__tablename__ = "users"
email: Mapped[str] = mapped_column(unique=True, index=True)
email_verified: Mapped[bool] = mapped_column(default=False)
scopes: Mapped[list[str] | None] = mapped_column(Json, default=None)
accounts: Mapped[list["Account"]] = relationship(
back_populates="user",
cascade="all, delete-orphan",
init=False,
)
class Account(DataclassBase, PrimaryKeyMixin, TimestampMixin):
__tablename__ = "accounts"
user_id: Mapped[UUID] = mapped_column(
ForeignKey("users.id", ondelete="cascade"),
nullable=False,
)
provider: Mapped[str]
provider_account_id: Mapped[str]
user: Mapped[User] = relationship(
back_populates="accounts",
lazy="selectin",
init=False,
)
Design Principles
- Building blocks, not frameworks - You own your models completely
- Sensible defaults - UTC datetimes, UUIDs, timestamps by default
- Dataclass-friendly - Clean instantiation and repr
- Dialect-aware - Use the best type for each database
- Minimal magic - Clear, explicit behavior
Migration from impl/auth.py
If you previously imported models from belgie_alchemy.impl.auth:
Before:
from belgie_alchemy.impl.auth import User, Account, Session, OAuthState
After:
# Copy models from examples/alchemy/auth_models.py to your project
# Then import from your own code:
from myapp.models import User, Account, Session, OAuthState
This gives you full control to customize the models for your application.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file belgie_alchemy-0.6.3.tar.gz.
File metadata
- Download URL: belgie_alchemy-0.6.3.tar.gz
- Upload date:
- Size: 6.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
31d1184f82e80d3376639a693135d6c5cfa899c31c30c411eb8d032daaa002ca
|
|
| MD5 |
092af98fd2a5b90823f14adfb3ba4d84
|
|
| BLAKE2b-256 |
7323ce7e03d5d74e6c6156a5bbf8e2053e7ef820941af2de11e541068b538c54
|
File details
Details for the file belgie_alchemy-0.6.3-py3-none-any.whl.
File metadata
- Download URL: belgie_alchemy-0.6.3-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35c1c1e65c05b5b4058d974f33f9788599dc0d3a62cb78c463617bff95c2b142
|
|
| MD5 |
13e0396118b3b1ea9d32b74fe9e8d634
|
|
| BLAKE2b-256 |
3a87a3c4cd1ebb68c1e515d10d1938d941a4d6abf50180330bc11ad69b0e21dc
|