Source code for app.models.project_model

from typing import TYPE_CHECKING, List
from sqlalchemy.orm import Mapped, mapped_column, validates, relationship
from sqlalchemy import select, Enum

from app.extensions import db

from app.utils import is_valid_datestring, slugify, ProjectStateEnum

if TYPE_CHECKING:
    from app.schemas.project_schema import ProjectSchema
    from app.models.project_participation_model import ProjectParticipation


[docs] class Project(db.Model): __tablename__ = "projects" id: Mapped[int] = mapped_column(primary_key=True) _name: Mapped[str] = mapped_column("name", unique=True) slug: Mapped[str] = mapped_column(unique=True) state: Mapped[ProjectStateEnum] = mapped_column(Enum(ProjectStateEnum, native_enum=False)) start_date: Mapped[str] = mapped_column() end_date: Mapped[str] = mapped_column(nullable=True) description: Mapped[str] = mapped_column(nullable=True) project_participations: Mapped[List["ProjectParticipation"]] = relationship("ProjectParticipation", back_populates="project", cascade="all, delete-orphan", passive_deletes=True)
[docs] @classmethod def from_schema(cls, schema: "ProjectSchema"): data = schema.model_dump() if "slug" in data: del data["slug"] return cls(**data)
def __init__(self, *, name=None, state=None, start_date=None, end_date=None, description=None): self.name = name self.state = state self.start_date = start_date self.end_date = end_date self.description = description @property def name(self): return self._name @name.setter def name(self, value): self._name = self.validate_name("name", value) self.slug = slugify(value)
[docs] @validates("name") def validate_name(self, k, v): if not isinstance(v, str): raise ValueError(f"Invalid name type: '{type(v)}'") if isinstance(v, str) and not 2 <= len(v) <= 64: raise ValueError(f"Invalid name length, minimum 2 and maximum 64 characters: '{v}'") return v
[docs] @validates("state") def validate_state(self, k, v): if not isinstance(v, ProjectStateEnum): raise ValueError(f"Invalid state type: '{type(v)}'") return v
[docs] @validates("start_date") def validate_start_date(self, k, v): if not isinstance(v, str): raise ValueError(f"Invalid start_date type: '{type(v)}'") if not is_valid_datestring(v): raise ValueError(f"Invalid start_date format, expected 'YYYY-MM-DD': '{v}'") return v
[docs] @validates("end_date") def validate_end_date(self, k, v): if v is None: return None if not isinstance(v, str): raise ValueError(f"Invalid end_date type: '{type(v)}'") if not is_valid_datestring(v): raise ValueError(f"Invalid end_date format, expected 'YYYY-MM-DD': '{v}'") return v
[docs] @validates("description") def validate_description(self, k, v): if v is None: return None if not isinstance(v, str): raise ValueError(f"Invalid {k} type: '{type(v)}'") if len(v) > 2048: raise ValueError(f"Invalid {k} length, minimum 0 and maximum 2048 characters: '{v}'") return v
def __repr__(self): return f"<{self.__class__.__name__}({', '.join(f'{k}={v!r}' for k, v in self.__dict__.items())})>"