45 lines
1.2 KiB
Python
45 lines
1.2 KiB
Python
|
|
from sqlalchemy.orm import DeclarativeBase, declared_attr, Mapped, mapped_column, relationship, add_mapped_attribute
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
def to_snake_case(name: str) -> str:
|
||
|
|
return "".join(["_" + i.lower() if i.isupper() else i for i in name]).lstrip("_")
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
def bidirectional_relationship(cls, foreign_table_cls):
|
||
|
|
"""Create a bidirectional relationship between two table-classes."""
|
||
|
|
|
||
|
|
column_name = f"{to_snake_case(cls.__name__)}"
|
||
|
|
column_name = f"{column_name}es" if column_name.endswith("s") else f"{column_name}s"
|
||
|
|
|
||
|
|
add_mapped_attribute(
|
||
|
|
foreign_table_cls,
|
||
|
|
column_name,
|
||
|
|
relationship(cls,
|
||
|
|
back_populates=foreign_table_cls.__tablename__,
|
||
|
|
cascade="all, delete-orphan",
|
||
|
|
collection_class=set,
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
return relationship(foreign_table_cls.__name__, back_populates=column_name)
|
||
|
|
|
||
|
|
|
||
|
|
class Base(DeclarativeBase):
|
||
|
|
__abstract__ = True
|
||
|
|
|
||
|
|
id: Mapped[int] = mapped_column(primary_key=True, sort_order=-1000000)
|
||
|
|
|
||
|
|
# noinspection PyMethodParameters
|
||
|
|
@declared_attr.directive
|
||
|
|
def __tablename__(cls) -> str:
|
||
|
|
"""Default table name in Database is derived from Class Name"""
|
||
|
|
return to_snake_case(cls.__name__)
|
||
|
|
|
||
|
|
|
||
|
|
# noinspection PyPep8Naming
|
||
|
|
|
||
|
|
|
||
|
|
|