Table column annotations for SQLAlchemy
Project description
Table column annotations for SQLAlchemy
Table column annotations for SQLAlchemy
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
Links
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]
# equivalent to
# id: Mapped[str] = mapped_column(sa.Text(), primary_key=True)
name: Mapped[TextColumn]
# equivalent to
# name: Mapped[str] = mapped_column(sa.Text(), default='')
email: Mapped[TextUniqueColumn]
# equivalent to
# email: Mapped[str] = mapped_column(sa.Text(), unique=True)
ext_id: Mapped[TextIndexColumn]
# equivalent to
# 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]
# equivalent to
# id: Mapped[str] = mapped_column(sa.Uuid(), primary_key=True, default=uuid4)
token: Mapped[UUIDIndexColumn]
# equivalent to
# token: Mapped[str] = mapped_column(sa.Uuid(), index=True, default=uuid4)
ext_id: Mapped[UUIDColumn]
# equivalent to
# 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]
# equivalent to
# birthday: Mapped[date] = mapped_column(sa.Date())
start_at: Mapped[TimeColumn]
# equivalent to
# start_at: Mapped[time] = mapped_column(sa.Time(timezone=True))
notify_at: Mapped[TimeWOTimezoneColumn]
# equivalent to
# notify_at: Mapped[time] = mapped_column(sa.Time(timezone=False))
approved_at: Mapped[DateTimeColumn]
# equivalent to
# approved_at: Mapped[datetime] = mapped_column(sa.DateTime(timezone=True))
failed_at: Mapped[DateTimeWOTimezoneColumn]
# equivalent to
# failed_at: Mapped[datetime] = mapped_column(sa.DateTime(timezone=False))
created_at: Mapped[DateTimeDefaultUtcNowColumn]
# equivalent to
# 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]
# equivalent to
# is_active: Mapped[bool] = mapped_column(Boolean())
is_confirmed: Mapped[BooleanDefaultFalseColumn]
# equivalent to
# is_confirmed: Mapped[bool] = mapped_column(Boolean(), default=False)
is_visible: Mapped[BooleanDefaultTrueColumn]
# equivalent to
# is_visible: Mapped[bool] = mapped_column(Boolean(), default=True)
String enums (VARCHAR)
This annotation will not create a native enum
The column will be VARCHAR (without length limit) so that you can easily update your enum
BooleanColumn–BOOLEANBooleanDefaultFalseColumn–BOOLEANwithdefault=FalseBooleanDefaultTrueColumn–BOOLEANwithdefault=True
from enum import StrEnum
from sqlalchemy.orm import Mapped
from sqlalchemy_annotations import StrEnumColumn
class UserStatus(StrEnum):
REGISTERED = 'REGISTERED'
ACTIVATED = 'ACTIVATED'
BANNED = 'BANNED'
class Model(Base):
...
status: Mapped[StrEnumColumn[UserStatus]]
# equivalent to
# status: Mapped[UserStatus] = mapped_column(Enum(UserStatus, native_enum=False, length=None))
A note on contribution
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
Thank you!
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.2.tar.gz.
File metadata
- Download URL: sqlalchemy_annotations-0.0.2.tar.gz
- Upload date:
- Size: 7.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74533ed688a82e5b0d01b3909512e898be823ab9f19c4404a2c1ebcacf93d319
|
|
| MD5 |
5096fdc290818322fa60cb9a8461720c
|
|
| BLAKE2b-256 |
b0d80f9f62e1485c5c59ea1a9a34115410e9cf8915d9f021f695574198e531f1
|
File details
Details for the file sqlalchemy_annotations-0.0.2-py3-none-any.whl.
File metadata
- Download URL: sqlalchemy_annotations-0.0.2-py3-none-any.whl
- Upload date:
- Size: 7.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12416461a35c13e7a86ab4ff554a09c7374981f87c2cdc73b45e0c6687d69bcd
|
|
| MD5 |
152082f00147428323c088ab6d26367b
|
|
| BLAKE2b-256 |
7062c80555e64e09af782c6494eca6ac590fdd3998402b4916a3ee9320fbfb2c
|