Files
stu_teacher/dao/scores_dao.py
T

91 lines
3.4 KiB
Python

# dao/scores_dao.py
# 成绩表的数据访问层(录入、修改、删除、查询 + 60分红线预警)
from typing import List, Optional, Tuple
from sqlalchemy.orm import Session
from model.scores import Score
from model.students import Student
from scheme.scores import ScoreAdd
class ScoreDAO:
WARNING_LINE = 60 # 成绩红线
@staticmethod
def get_one(db: Session, stu_id: int, exam_id: int, include_deleted: bool = False) -> Optional[Score]:
"""获取指定学生某次考核的成绩(复合主键查询)"""
query = db.query(Score).filter(Score.stu_id == stu_id, Score.exam_id == exam_id)
if not include_deleted:
query = query.filter(Score.is_deleted == 0)
return query.first()
@staticmethod
def add_score(db: Session, score_data: ScoreAdd) -> Score:
"""录入成绩(调用方需先校验学生存在与复合主键冲突)"""
db_score = Score(**score_data.model_dump(), is_deleted=0)
db.add(db_score)
db.commit()
db.refresh(db_score)
return db_score
@staticmethod
def update_score(db: Session, stu_id: int, exam_id: int, new_score: float) -> Optional[Score]:
"""修改指定学生的某次成绩"""
db_score = ScoreDAO.get_one(db, stu_id, exam_id)
if db_score is None:
return None
db_score.score = new_score
db_score.is_deleted = 0 # 若曾被软删除,修改视为恢复
db.commit()
db.refresh(db_score)
return db_score
@staticmethod
def delete_score(db: Session, stu_id: int, exam_id: int) -> bool:
"""
逻辑删除指定学生的某次成绩
:return: True 成功 / False 不存在或已删除
"""
db_score = ScoreDAO.get_one(db, stu_id, exam_id)
if db_score is None:
return False
db_score.is_deleted = 1
db.commit()
return True
@staticmethod
def get_by_student(db: Session, stu_id: int) -> List[Score]:
"""获取学生的全部成绩(按考核序次排序)"""
return (
db.query(Score)
.filter(Score.stu_id == stu_id, Score.is_deleted == 0)
.order_by(Score.exam_id)
.all()
)
@staticmethod
def get_by_exam(db: Session, exam_id: int, skip: int = 0, limit: int = 100) -> Tuple[int, List[Score]]:
"""按考核序次查询成绩列表(分页)"""
query = db.query(Score).filter(Score.exam_id == exam_id, Score.is_deleted == 0)
total = query.count()
items = query.order_by(Score.stu_id).offset(skip).limit(limit).all()
return total, items
@staticmethod
def attach_student_name(db: Session, score: Score) -> None:
"""把学生姓名附加到 Score 对象上(供响应模型冗余展示)"""
student = db.query(Student).filter(Student.stu_id == score.stu_id).first()
score.stu_name = student.stu_name if student else None
@staticmethod
def build_score_item(score: Score, stu_name: Optional[str] = None) -> dict:
"""组装成绩响应字典:附带红线预警标记"""
return {
"stu_id": score.stu_id,
"exam_id": score.exam_id,
"score": score.score,
"stu_name": stu_name,
"is_warning": score.score is not None and score.score < ScoreDAO.WARNING_LINE,
}