"""成绩表(需求 2.2):一个学生 N 次考核,一对多。 红线预警:录入分数低于及格线时 flag=1,并往学生备注里追加一条提醒, 统计模块的"多次不及格"直接按 flag 聚合,不用每次临时算阈值。 """ from __future__ import annotations from datetime import date from decimal import Decimal from sqlalchemy import Date, ForeignKey, Numeric, SmallInteger, String, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from app.model.base import Base, SoftDeleteMixin, TimestampMixin from app.model.constants import ScoreFlag class Score(Base, TimestampMixin, SoftDeleteMixin): __tablename__ = "score" __table_args__ = ( UniqueConstraint("stu_id", "exam_seq", name="uk_score_stu_seq"), {"comment": "学生考核成绩表"}, ) id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) stu_id: Mapped[int] = mapped_column(ForeignKey("student.id"), nullable=False, index=True, comment="学生ID") exam_seq: Mapped[int] = mapped_column(SmallInteger, nullable=False, index=True, comment="考核序次(第几次考核)") exam_name: Mapped[str | None] = mapped_column(String(50), comment="考核名称,如 阶段一考试") exam_date: Mapped[date | None] = mapped_column(Date, comment="考核日期") score: Mapped[Decimal] = mapped_column(Numeric(5, 2), nullable=False, comment="成绩") flag: Mapped[int] = mapped_column( SmallInteger, default=int(ScoreFlag.NORMAL), nullable=False, index=True, comment="预警标记 0=正常 1=低于红线需重点关注", ) remark: Mapped[str | None] = mapped_column(String(255), comment="备注") student: Mapped["Student"] = relationship(back_populates="scores", lazy="joined") # noqa: F821 # ---------------- 出参派生字段 ---------------- @property def is_warning(self) -> bool: return self.flag == int(ScoreFlag.WARNING) @property def student_name(self) -> str | None: return self.student.name if self.student else None @property def class_name(self) -> str | None: return self.student.class_name if self.student else None