Created
May 12, 2024 01:12
-
-
Save hasansezertasan/691a7ef67cc79ea669ff76d168503235 to your computer and use it in GitHub Desktop.
How to use SQLAlchemy with numerical enums?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
How to use SQLAlchemy with numerical enums? | |
`IntEnum` class is taken from this article: [Using Python enums in SQLAlchemy models](https://michaelcho.me/article/using-python-enums-in-sqlalchemy-models/), all credits to the author. | |
""" | |
import datetime | |
import enum | |
from sqlalchemy import Integer, TypeDecorator, create_engine | |
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column | |
from starlette.applications import Starlette | |
from starlette_admin.contrib.sqla import Admin, ModelView | |
from starlette_admin.fields import EnumField | |
engine = create_engine( | |
"sqlite:///db.sqlite3", connect_args={"check_same_thread": False} | |
) | |
class IntEnum(TypeDecorator): | |
""" | |
Enables passing in a Python enum and storing the enum's *value* in the db. | |
The default would have stored the enum's *name* (ie the string). | |
""" | |
impl = Integer | |
def __init__(self, enumtype, *args, **kwargs): | |
super(IntEnum, self).__init__(*args, **kwargs) | |
self._enumtype = enumtype | |
def process_bind_param(self, value, dialect): | |
if isinstance(value, int): | |
return value | |
return value.value | |
def process_result_value(self, value, dialect): | |
return self._enumtype(value) | |
class Gender(enum.IntEnum): | |
MALE = 1 | |
FEMALE = 2 | |
PREFER_NOT_TO_SAY = 3 | |
class Base(DeclarativeBase): | |
pass | |
class Mixin: | |
id: Mapped[int] = mapped_column( | |
primary_key=True, | |
autoincrement=True, | |
index=True, | |
unique=True, | |
) | |
date_created: Mapped[datetime.datetime] = mapped_column( | |
default=datetime.datetime.utcnow, | |
index=True, | |
) | |
date_updated: Mapped[datetime.datetime] = mapped_column( | |
default=datetime.datetime.utcnow, | |
onupdate=datetime.datetime.utcnow, | |
index=True, | |
) | |
class Person(Base, Mixin): | |
__tablename__ = "person" | |
name: Mapped[str] | |
gender: Mapped[Gender] = mapped_column(IntEnum(Gender)) | |
class PersonView(ModelView): | |
fields = [ | |
"name", | |
EnumField( | |
name="gender", | |
coerce=int, | |
choices=[ | |
(1, "Male"), | |
(2, "Female"), | |
(3, "Perefer not to say"), | |
], | |
), | |
] | |
with engine.connect() as conn: | |
person = Person(name="John Doe", gender=1) | |
Base.metadata.create_all(engine) | |
app = Starlette() | |
admin = Admin(engine, title="SQLAlchemy Numerical Enum Example") | |
admin.add_view(PersonView(Person)) | |
admin.mount_to(app) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
starlette-admin | |
sqlalchemy | |
uvicorn |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
for the ones want to do with
Column
, I did this way;note:
nullable
is optional