# dao/teacher_dao.py # 教师信息数据访问层 from typing import List, Optional, Tuple from sqlalchemy.orm import Session from dao.exceptions import ConflictError, NotFoundError from dao.pagination import paginate from model.teacher_model import Teacher def assert_teacher_alive(db: Session, tea_id: str, detail: Optional[str] = None) -> Teacher: """ 确认教师存在且未删除,否则抛 NotFoundError。 供班级模块复用作外键校验。 """ teacher = db.query(Teacher).filter(Teacher.id == tea_id, Teacher.is_deleted == 0).first() if not teacher: raise NotFoundError(detail or f"教师 {tea_id} 不存在") return teacher def list_teachers( db: Session, page: int, size: int, name: Optional[str] = None, type: Optional[str] = None, ) -> Tuple[int, List[Teacher]]: """分页查询教师,支持按姓名模糊、按职位过滤。""" query = db.query(Teacher).filter(Teacher.is_deleted == 0) if name: query = query.filter(Teacher.name.like(f"%{name}%")) if type: query = query.filter(Teacher.type == type) return paginate(query, page, size, order_by=Teacher.id) def create_teacher(db: Session, data: dict) -> Teacher: """新增教师:校验编号与电话唯一。""" # 编号是主键,已软删除的记录同样占用该编号,所以这里不加 is_deleted 过滤 if db.query(Teacher).filter(Teacher.id == data["id"]).first(): raise ConflictError("教师编号已存在") if db.query(Teacher).filter(Teacher.phone == data["phone"], Teacher.is_deleted == 0).first(): raise ConflictError("电话已被使用") teacher = Teacher(**data) db.add(teacher) db.commit() db.refresh(teacher) return teacher def update_teacher(db: Session, tea_id: str, data: dict) -> Teacher: """更新教师:若改电话需重新校验唯一。""" teacher = assert_teacher_alive(db, tea_id, "教师不存在或已删除") new_phone = data.get("phone") if new_phone and new_phone != teacher.phone: if db.query(Teacher).filter(Teacher.phone == new_phone, Teacher.is_deleted == 0).first(): raise ConflictError("电话已被使用") for field, value in data.items(): setattr(teacher, field, value) db.commit() db.refresh(teacher) return teacher def soft_delete_teacher(db: Session, tea_id: str) -> None: """软删除教师:仅置 is_deleted 标记,数据保留。""" teacher = assert_teacher_alive(db, tea_id, "教师不存在或已删除") teacher.is_deleted = 1 db.commit()