145 lines
4.1 KiB
Python
145 lines
4.1 KiB
Python
from typing import TYPE_CHECKING, Optional
|
|
|
|
from sqlalchemy import ForeignKey, Table, Column
|
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from models.base import BaseModel
|
|
from models.mixins import IdMixin, SoftDeleteMixin
|
|
|
|
if TYPE_CHECKING:
|
|
from models import Module, Deal
|
|
|
|
|
|
module_attribute = Table(
|
|
"module_attribute",
|
|
BaseModel.metadata,
|
|
Column("module_id", ForeignKey("modules.id"), primary_key=True),
|
|
Column("attribute_id", ForeignKey("attributes.id"), primary_key=True),
|
|
)
|
|
|
|
|
|
class AttributeType(BaseModel, IdMixin, SoftDeleteMixin):
|
|
__tablename__ = "attribute_types"
|
|
|
|
type: Mapped[str] = mapped_column(unique=True)
|
|
name: Mapped[str] = mapped_column(unique=True)
|
|
|
|
attributes: Mapped["Attribute"] = relationship(
|
|
back_populates="type",
|
|
lazy="noload",
|
|
)
|
|
|
|
|
|
class Attribute(BaseModel, IdMixin, SoftDeleteMixin):
|
|
__tablename__ = "attributes"
|
|
|
|
label: Mapped[str] = mapped_column()
|
|
is_applicable_to_group: Mapped[bool] = mapped_column(
|
|
default=False,
|
|
comment="Применять ли изменения атрибута карточки ко всем карточкам в группе",
|
|
)
|
|
is_shown_on_dashboard: Mapped[bool] = mapped_column(
|
|
default=False,
|
|
comment="Отображается ли атрибут на дашборде",
|
|
)
|
|
is_highlight_if_expired: Mapped[bool] = mapped_column(
|
|
default=False,
|
|
comment="Подсветка атрибута, если Дата/ДатаВремя просрочена",
|
|
)
|
|
is_nullable: Mapped[bool] = mapped_column(default=False)
|
|
default_value: Mapped[Optional[dict[str, any]]] = mapped_column(JSONB)
|
|
description: Mapped[str] = mapped_column(default="")
|
|
|
|
is_built_in: Mapped[bool] = mapped_column(default=False)
|
|
|
|
type_id: Mapped[int] = mapped_column(ForeignKey("attribute_types.id"))
|
|
type: Mapped[AttributeType] = relationship(
|
|
back_populates="attributes",
|
|
lazy="joined",
|
|
)
|
|
|
|
modules: Mapped[list["Module"]] = relationship(
|
|
secondary=module_attribute,
|
|
back_populates="attributes",
|
|
lazy="noload",
|
|
)
|
|
|
|
values: Mapped[list["AttributeValue"]] = relationship(
|
|
uselist=True,
|
|
back_populates="attribute",
|
|
lazy="noload",
|
|
)
|
|
|
|
|
|
class AttributeValue(BaseModel):
|
|
__tablename__ = "attribute_values"
|
|
|
|
id: Mapped[int] = mapped_column(
|
|
primary_key=True,
|
|
autoincrement=True,
|
|
)
|
|
|
|
value: Mapped[Optional[dict[str, any]]] = mapped_column(JSONB)
|
|
|
|
deal_id: Mapped[int] = mapped_column(
|
|
ForeignKey("deals.id"),
|
|
primary_key=True,
|
|
)
|
|
deal: Mapped["Deal"] = relationship(
|
|
back_populates="attributes_values",
|
|
lazy="noload",
|
|
)
|
|
|
|
module_id: Mapped[int] = mapped_column(
|
|
ForeignKey("modules.id"),
|
|
primary_key=True,
|
|
)
|
|
module: Mapped["Module"] = relationship(
|
|
back_populates="attribute_values",
|
|
lazy="noload",
|
|
)
|
|
|
|
attribute_id: Mapped[int] = mapped_column(
|
|
ForeignKey("attributes.id"),
|
|
primary_key=True,
|
|
)
|
|
attribute: Mapped[Attribute] = relationship(
|
|
back_populates="values",
|
|
lazy="joined",
|
|
)
|
|
|
|
def set_value(self, value: Optional[dict | str | bool | int | float]):
|
|
if value is None:
|
|
return
|
|
self.value = {"value": value}
|
|
|
|
def get_value(self) -> Optional[dict | str | bool | int | float]:
|
|
if self.value is None:
|
|
return None
|
|
return self.value["value"]
|
|
|
|
|
|
class AttributeLabel(BaseModel):
|
|
__tablename__ = "attribute_labels"
|
|
|
|
label: Mapped[str] = mapped_column()
|
|
|
|
module_id: Mapped[int] = mapped_column(
|
|
ForeignKey("modules.id"),
|
|
primary_key=True,
|
|
)
|
|
module: Mapped["Module"] = relationship(
|
|
backref="attribute_labels",
|
|
lazy="noload",
|
|
)
|
|
|
|
attribute_id: Mapped[int] = mapped_column(
|
|
ForeignKey("attributes.id"),
|
|
primary_key=True,
|
|
)
|
|
attribute: Mapped[Attribute] = relationship(
|
|
backref="attribute_labels",
|
|
lazy="joined",
|
|
)
|