Table column annotations for SQLAlchemy (v2)
Project description
Table column annotations for SQLAlchemy
Table column annotations for SQLAlchemy (v2)
Instead of this:
from datetime import UTC, datetime
from uuid import UUID, uuid4
import sqlalchemy as sa
from sqlalchemy.orm import Mapped, mapped_column
class User(Base):
id: Mapped[int] = mapped_column(sa.Integer(), sa.Identity(always=True), primary_key=True)
email: Mapped[str] = mapped_column(sa.Text(), unique=True, default='')
confirmed: Mapped[bool] = mapped_column(sa.Boolean(), default=False)
connection_id: Mapped[int | None] = mapped_column(sa.BigInteger(), index=True)
token: Mapped[UUID | None] = mapped_column(sa.Uuid(), index=True, default=uuid4)
created_at: Mapped[datetime] = mapped_column(sa.DateTime(timezone=True), default=lambda: datetime.now(tz=UTC))
you can declare your SQLAlchemy models like so:
import sqlalchemy_annotations as saa
from sqlalchemy.orm import Mapped
class User(Base):
id: Mapped[saa.IntegerPKColumn]
email: Mapped[saa.TextUniqueColumn]
confirmed: Mapped[saa.BooleanDefaultFalseColumn]
connection_id: Mapped[saa.BigIntegerIndexColumn | None]
token: Mapped[saa.UUIDIndexColumn | None]
created_at: Mapped[saa.DateTimeDefaultUtcNowColumn]
What are these IntegerPKColumn, BigIntegerIndexColumn, BooleanDefaultFalseColumn and other ones?
These are just type aliases created with typing.Annotated function that adds context-specific metadata to a type,
so that you don't need to specify all these extra assignments to mapped_column function
Examples
Integers (INTEGER, BIGINT, SERIAL, BIGSERIAL)
IntegerPKColumn/BigIntegerPKColumn–INTEGER / BIGINT, GENERATED ALWAYS AS IDENTITY, PRIMARY KEYSerialPKColumn/BigSerialPKColumn–SERIAL / BIGSERIAL, PRIMARY KEYIntegerColumn/BigIntegerColumn–INTEGER / BIGINTIntegerIndexColumn/BigIntegerIndexColumn–INTEGER / BIGINT, INDEX
from sqlalchemy.orm import Mapped
from sqlalchemy_annotations import IntegerColumn, IntegerIndexColumn, IntegerPKColumn
class Model(Base):
id: Mapped[IntegerPKColumn]
# equivalent to
# id: Mapped[int] = mapped_column(sa.Integer(), Identity(always=True), primary_key=True)
number: Mapped[IntegerColumn]
# equivalent to
# number: Mapped[int] = mapped_column(sa.Integer())
uid: Mapped[IntegerIndexColumn]
# equivalent to
# uid: Mapped[int] = mapped_column(sa.Integer(), index=True)
Strings (TEXT)
TextPKColumn–TEXT, PRIMARY KEYTextColumn–TEXTwithdefault=''TextUniqueColumn–TEXT, UNIQUETextIndexColumn–TEXT, INDEX
from sqlalchemy.orm import Mapped
from sqlalchemy_annotations import TextColumn, TextIndexColumn, TextPKColumn, TextUniqueColumn
class Model(Base):
id: Mapped[TextPKColumn]
# id: Mapped[str] = mapped_column(sa.Text(), primary_key=True)
name: Mapped[TextColumn]
# name: Mapped[str] = mapped_column(sa.Text(), default='')
email: Mapped[TextUniqueColumn]
# email: Mapped[str] = mapped_column(sa.Text(), unique=True)
ext_id: Mapped[TextIndexColumn]
# ext_id: Mapped[str] = mapped_column(sa.Text(), index=True)
UUID (UUID)
UUIDPKColumn–UUID, PRIMARY KEYwithdefault=uuid4UUIDIndexColumn–UUID, INDEXwithdefault=uuid4UUIDColumn–UUIDwithdefault=uuid4
from sqlalchemy.orm import Mapped
from sqlalchemy_annotations import UUIDColumn, UUIDIndexColumn, UUIDPKColumn
class Model(Base):
id: Mapped[UUIDPKColumn]
# id: Mapped[str] = mapped_column(sa.Uuid(), primary_key=True, default=uuid4)
token: Mapped[UUIDIndexColumn]
# token: Mapped[str] = mapped_column(sa.Uuid(), index=True, default=uuid4)
ext_id: Mapped[UUIDColumn]
# ext_id: Mapped[str] = mapped_column(sa.Uuid(), default=uuid4)
Date, Time, Datetime (DATE, TIME, TIMESTAMP)
DateColumn–DATETimeColumn–TIME WITH TIME ZONETimeWOTimezoneColumn–TIME WITHOUT TIME ZONEDateTimeColumn–TIMESTAMP WITH TIME ZONEDateTimeWOTimezoneColumn–TIMESTAMP WITHOUT TIME ZONEDateTimeDefaultUtcNowColumn–TIMESTAMP WITH TIME ZONEwithdefault=lambda: datetime.now(tz=UTC)
from sqlalchemy.orm import Mapped
from sqlalchemy_annotations import (
DateColumn,
DateTimeColumn,
DateTimeDefaultUtcNowColumn,
DateTimeWOTimezoneColumn,
TimeColumn,
TimeWOTimezoneColumn,
)
class Model(Base):
...
birthday: Mapped[DateColumn]
# birthday: Mapped[date] = mapped_column(sa.Date())
start_at: Mapped[TimeColumn]
# start_at: Mapped[time] = mapped_column(sa.Time(timezone=True))
notify_at: Mapped[TimeWOTimezoneColumn]
# notify_at: Mapped[time] = mapped_column(sa.Time(timezone=False))
approved_at: Mapped[DateTimeColumn]
# approved_at: Mapped[datetime] = mapped_column(sa.DateTime(timezone=True))
failed_at: Mapped[DateTimeWOTimezoneColumn]
# failed_at: Mapped[datetime] = mapped_column(sa.DateTime(timezone=False))
created_at: Mapped[DateTimeDefaultUtcNowColumn]
# created_at: Mapped[datetime] = mapped_column(sa.DateTime(timezone=True), default=lambda: datetime.now(tz=UTC))
Booleans (BOOLEAN)
BooleanColumn–BOOLEANBooleanDefaultFalseColumn–BOOLEANwithdefault=FalseBooleanDefaultTrueColumn–BOOLEANwithdefault=True
from sqlalchemy.orm import Mapped
from sqlalchemy_annotations import BooleanColumn, BooleanDefaultFalseColumn, BooleanDefaultTrueColumn
class Model(Base):
...
is_active: Mapped[BooleanColumn]
# is_active: Mapped[bool] = mapped_column(Boolean())
is_confirmed: Mapped[BooleanDefaultFalseColumn]
# is_confirmed: Mapped[bool] = mapped_column(Boolean(), default=False)
is_visible: Mapped[BooleanDefaultTrueColumn]
# is_visible: Mapped[bool] = mapped_column(Boolean(), default=True)
More complex example (and a note on contribution)
If you need to more functionality and flexibility, you still can use regular SQLAlchemy functionality:
from enum import StrEnum
import sqlalchemy as sa
from sqlalchemy.orm import Mapped, mapped_column
class UserKind(StrEnum):
GUEST = 'GUEST'
MODERATOR = 'MODERATOR'
ADMIN = 'ADMIN'
class User(Base):
id: Mapped[int] = mapped_column(sa.BigInteger(), sa.Identity(always=False), primary_key=True)
kind: Mapped[UserKind] = mapped_column(
sa.Enum(UserKind, native_enum=False, length=None),
default=UserKind.GUEST,
)
This is opensource project
So if you find something that you can add of fix, feel free to
open an issue
and raise a pull request
Good luck!
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 sqlalchemy_annotations-0.0.1.tar.gz.
File metadata
- Download URL: sqlalchemy_annotations-0.0.1.tar.gz
- Upload date:
- Size: 5.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0e65f26ce3c3535bc361a644965a404245fdbab26cb6f189670c8790f1e8cc4
|
|
| MD5 |
c3a79c82498a9842d10531fdecaac0cb
|
|
| BLAKE2b-256 |
41df65993bd7d321d2fbd1cedf8a79d519a12b409f26bf5734c80bd309204080
|
File details
Details for the file sqlalchemy_annotations-0.0.1-py3-none-any.whl.
File metadata
- Download URL: sqlalchemy_annotations-0.0.1-py3-none-any.whl
- Upload date:
- Size: 6.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df3e4da22d1426755ab4f1c4dbd1315701f0f43199896b81224efa250c64aca4
|
|
| MD5 |
ecb192cfe9682a93a3c6493a1d881a4c
|
|
| BLAKE2b-256 |
db06f832a050d1e37265a38c64976999a69ad8f38f2206828324979c20736d7c
|