From 883b287e668ec8a6b4d872e3f906f927f13fe935 Mon Sep 17 00:00:00 2001 From: wolin_zhangyi <1141397129@qq.com> Date: Mon, 21 Sep 2026 18:46:42 +0800 Subject: [PATCH 1/2] 1.teacher dao 2.class_teacher 3.teacher api 4.teacher models 5.teacher schemas --- api/teacher.py | 129 ++++++++++++++++++++++ dao/teacher.py | 239 ++++++++++++++++++++++++++++++++++++++++ models/class_teacher.py | 52 +++++++++ models/teacher.py | 44 -------- schemas/teacher.py | 41 ++++++- 5 files changed, 460 insertions(+), 45 deletions(-) diff --git a/api/teacher.py b/api/teacher.py index e69de29..19e5985 100644 --- a/api/teacher.py +++ b/api/teacher.py @@ -0,0 +1,129 @@ +from typing import List +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from core import database +from core.database import get_db +from schemas.teacher import TeacherOut, TeacherCreate, TeacherUpdate, ClassTeachersCreate, ClassTeacherOut +# 导入dao层所有函数 +from models.teacher import Teacher +from models.class_teacher import ClassTeachers +from dao.teacher import ( + get_teacher_list, + get_teacher_by_id, + create_teacher, + update_teacher, + delete_teacher, + get_class_teacher_by_class_id, + create_class_teacher, + update_class_teacher_full, + delete_class_teacher +) + +router = APIRouter(prefix="/teacher", tags=["老师管理模块"]) + +#===========================老师表=============================== +@router.get("/list", response_model=List[TeacherOut]) +def api_get_teacher_list(db: Session = Depends(get_db)): + """ + GET 查询全部有效老师列表 + :param db: 数据库会话,Depends自动注入 + :return: List[TeacherOut] 老师列表,使用TeacherOut做响应格式化 + """ + return get_teacher_list(db) + +@router.get("/{teacher_id}", response_model=TeacherOut) +def api_get_teacher_by_id(teacher_id: int,db: Session = Depends(get_db)): + """ + 根据老师主键ID查询单个有效老师 + :param teacher_id: int 老师表主键ID + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: TeacherOut 老师详情信息 + """ + return get_teacher_by_id(db,teacher_id) +@router.post("", response_model=TeacherOut, summary="新增老师") +def api_create_teacher(obj: TeacherCreate, db: Session = Depends(get_db)): + """ + 新增老师记录,自动校验姓名、编号唯一性,并自动生成老师业务编号 + :param obj: TeacherCreate Pydantic模型,前端提交新增老师表单数据 + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: TeacherOut 新增成功后的老师完整信息 + """ + return create_teacher(db, obj) +@router.put("/{teacher_id}", response_model=TeacherOut, summary="修改老师信息(局部更新)") +def api_update_teacher(teacher_id: int, obj: TeacherUpdate, db: Session = Depends(get_db)): + """ + 修改老师信息,支持局部更新,仅更新前端传入的字段 + :param teacher_id: int 需要修改的老师主键ID + :param obj: TeacherUpdate Pydantic模型,前端提交待修改字段 + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: TeacherOut 更新后的老师完整信息 + """ + db_teacher = get_teacher_by_id(db, teacher_id) + if not db_teacher: + raise HTTPException(status_code=404, detail="老师不存在或已删除!") + result = update_teacher(db, teacher_id, obj) + return result +@router.delete("/{teacher_id}", summary="逻辑删除老师") +def api_delete_teacher(teacher_id: int, db: Session = Depends(get_db)): + """ + 逻辑删除老师,存在有效班级带班关系时禁止删除 + :param teacher_id: int 需要删除的老师主键ID + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: dict 操作成功提示 + """ + result = delete_teacher(db, teacher_id) + if not result: + raise HTTPException(status_code=404, detail="老师不存在或已删除!") + return {"msg": "老师逻辑删除成功"} + +# ===================== 班级老师关联路由组 ===================== +class_teacher_router = APIRouter(prefix="/class-teacher", tags=["班级老师分配管理模块"]) + +@class_teacher_router.get("/class/{class_id}", response_model=List[ClassTeacherOut], summary="根据班级ID查询该班级所有带班老师") +def api_get_class_teacher_by_class_id(class_id: int, db: Session = Depends(get_db)): + """ + 根据班级主键ID,查询该班级全部有效的班级-老师绑定记录 + :param class_id: int 班级表主键ID + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: List[ClassTeachersOut] 班级老师关联记录列表 + """ + return get_class_teacher_by_class_id(db, class_id) + +@class_teacher_router.post("", response_model=ClassTeacherOut, summary="分配老师到班级,新增班级老师关联记录") +def api_create_class_teacher(obj: ClassTeachersCreate, db: Session = Depends(get_db)): + """ + 新增班级与老师的绑定关系,做重复性校验与老师有效性校验 + :param obj: ClassTeachersCreate Pydantic模型,前端提交class_id、teacher_id、role + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: ClassTeachersOut 新增成功后的班级老师关联记录 + """ + return create_class_teacher(db, obj) + +@class_teacher_router.put("/{rel_id}", response_model=ClassTeacherOut, summary="更新班级老师绑定关系") +def api_update_class_teacher_full(rel_id: int, obj: ClassTeachersCreate, db: Session = Depends(get_db)): + """ + 修改班级老师中间表记录,支持修改class_id、teacher_id、role;自动校验老师有效性、三元组合唯一性 + :param rel_id: int class_teachers中间表主键ID(待修改的关联记录id) + :param obj: ClassTeachersCreate Pydantic模型,前端提交新的class_id、teacher_id、role + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: ClassTeachersOut 更新后的班级老师关联记录 + """ + result = update_class_teacher_full(db, rel_id, obj) + if not result: + raise HTTPException(status_code=404, detail="班级老师关联记录不存在!") + return result + +@class_teacher_router.delete("/{rel_id}", summary="逻辑删除班级老师带班关联") +def api_delete_class_teacher(rel_id: int, db: Session = Depends(get_db)): + """ + 逻辑删除班级老师绑定关系,修改is_deleted标记为1,非物理删除 + :param rel_id: int class_teachers中间表主键ID + :param db: Session 数据库会话对象,依赖注入自动获取 + :return: dict 操作成功提示 + """ + result = delete_class_teacher(db, rel_id) + if not result: + raise HTTPException(status_code=404, detail="班级老师关联记录不存在!") + return {"msg": "解除班级带班关系成功"} + + diff --git a/dao/teacher.py b/dao/teacher.py index e69de29..239c3d5 100644 --- a/dao/teacher.py +++ b/dao/teacher.py @@ -0,0 +1,239 @@ +from sqlalchemy.orm import Session +from core import database +from models.teacher import Teacher +from models.class_teacher import ClassTeachers +from schemas.teacher import TeacherUpdate, TeacherCreate,ClassTeachersCreate +from utils.code_generator import generate_no +from fastapi import HTTPException + +''' +本文件内容为老师表与班级老师关系表的增删改查函数集合 +''' +#================老师表Teacher的CRUD================ +#查询所有未被删除的老师 +def get_teacher_list(db:Session, teacher_id:int): + teacher = get_teacher_by_id(db, teacher_id) + if not teacher: + raise HTTPException(status_code=404, detail="老师不存在或已删除!") + #查询老师列表,过滤逻辑删除 + return db.query(Teacher).filter(Teacher.is_deleted == 0).all() +#根据id,查询单个符合条件的老师 +def get_teacher_by_id(db:Session,teacher_id:int): + return db.query(Teacher).filter(Teacher.id == teacher_id + ,Teacher.is_deleted == 0).first() +#新增 +def create_teacher(db:Session,obj:TeacherCreate): + ''' + 新增 + :param db: Session 数据库会话 + :param obj:TeacherCreate 前端传入新增数据 + :return: db_teacher 新增成功的ORM对象 + 业务逻辑: + 1、查重:同名有效老师不能重复新增 + 2、如果前端手动添加teacher_no,校验编号不能和已有有效老师编号重复 + 3、创建ORM对象加入会话 + 4、调用generate_no,走动生成业务编号 + 5、commit提交事务入库,refresh刷新对象 + ''' + exist_teacher = db.query(Teacher).filter(Teacher.teacher_name == obj.teacher_name + ,Teacher.is_deleted == 0).first() + if exist_teacher: + raise HTTPException(status_code=409,detail='该用户已存在') + if obj.teacher_no: + exist_teacher = db.query(Teacher).filter(Teacher.teacher_no == obj + .teacher_no,Teacher.is_deleted == 0).first() + if exist_teacher: + raise HTTPException(status_code=409,detail='老师编号已存在') + #开始添加 + data = obj.model_dump(exclude_none=True) + db_teacher = Teacher(**data) + db.add(db_teacher) + # 调用公共函数生成业务编号,内部执行db.flush拿到自增id + generate_no('teacher_no','TCH',db_teacher,db) + db.commit() + db.refresh(db_teacher) + #从数据库重新查询这条记录,刷新 db_teacher 对象。 + #作用:同步数据库默认字段的值,例如`created_at`、`updated_at`,拿到数据库里最新的数据, + # 最终返回给前端。 + return db_teacher +#更新 +def update_teacher(db:Session,teacher_id:int,obj:TeacherUpdate): + """ + 修改老师信息,局部更新 + :param db: Session 数据库会话 + :param teacher_id: int 需要修改的老师id + :param obj: TeacherUpdate 前端传入要修改的字段 + :return: db_teacher ORM对象 / None + """ + # 调用get_teacher_by_id校验用户是否存在 + db_teacher = get_teacher_by_id(db,teacher_id) + if obj.teacher_name: + exist_teacher = db.query(Teacher).filter( + Teacher.teacher_name == obj.teacher_name, + Teacher.id != teacher_id, + Teacher.is_deleted == 0 + ).first() + if exist_teacher: + raise HTTPException(status_code=409, detail="该姓名已被其他老师占用!") + if obj.teacher_no: + exist_no = db.query(Teacher).filter( + Teacher.teacher_no == obj.teacher_no, + Teacher.id != teacher_id, + Teacher.is_deleted == 0 + ).first() + if exist_no: + raise HTTPException(status_code=409, detail="老师编号已被其他老师占用!") + #用户存在,解析键值对,循环使用setattr添加 + update_data = obj.model_dump(exclude_none=True) + for k, v in update_data.items(): + setattr(db_teacher, k, v) + db.commit() + db.refresh(db_teacher) + return db_teacher +#删除 +def delete_teacher(db:Session,teacher_id:int): + """ + 逻辑删除老师,不是物理删除;修改is_deleted=1 + :param db: Session + :param teacher_id:老师主键id + :return: Teacher ORM对象,找不到返回None + 业务限制:老师已经分配班级,则不允许删除,防止脏数据 + """ + # 查询目标老师 + db_teacher = get_teacher_by_id(db, teacher_id) + if not db_teacher: + return None + + # 校验:查询班级老师中间表,判断该老师是否还有有效带班关系 + rel = db.query(ClassTeachers).filter( + ClassTeachers.teacher_id == teacher_id, + ClassTeachers.is_deleted == 0 + ).first() + if rel: + raise HTTPException( + status_code=400, + detail="该老师已分配班级,不能删除,请先解除带班关系!" + ) + + # 逻辑删除标记 + db_teacher.is_deleted = 1 + db.commit() + return db_teacher + +#==================班级老师中间表 CRUD===================== +#查询 +def get_class_teacher_by_class_id(db: Session, class_id: int): + """ + 根据班级id,查询该班级所有有效的带班老师关系 + :param db: Session + :param class_id:班级主键 + :return: list[ClassTeacher] + """ + return ( + db.query(ClassTeachers) + .filter(ClassTeachers.class_id == class_id + ,ClassTeachers.is_deleted == 0) + .all() + ) + +#新增 +def create_class_teacher(db: Session, obj: ClassTeachersCreate): + """ + 分配老师到班级,新增班级-老师关系记录 + :param db: Session + :param obj: ClassTeacherCreate class_id、teacher_id、role + :return: ClassTeacher ORM对象 + 校验: + 1.老师必须存在且未删除 + 2.同一班级同一个老师同一个角色不能重复分配 + """ + # 校验老师是否存在 + teacher = get_teacher_by_id(db, obj.teacher_id) + if not teacher: + raise HTTPException(status_code=404, detail="老师不存在或已删除!") + + # 查重:同一班级+同一老师+同一角色不能重复分配 + rel = db.query(ClassTeachers).filter( + ClassTeachers.class_id == obj.class_id, + ClassTeachers.teacher_id == obj.teacher_id, + ClassTeachers.role == obj.role, + ClassTeachers.is_deleted == 0 + ).first() + if rel: + raise HTTPException(status_code=409, detail="该老师已以相同角色分配到该班级!") + + data = obj.model_dump() + db_obj = ClassTeachers(**data) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + + return db_obj + +#更新 +def update_class_teacher_full(db: Session, rel_id: int, obj: ClassTeachersCreate): + """ + 完整更新班级老师关系:可修改 class_id、teacher_id、role + :param db: Session + :param rel_id: 中间表主键 + :param obj: ClassTeacherCreate 传入的新参数 + :return: ClassTeacher ORM对象 + 校验: + 1. 关系记录存在且未删除 + 2. 如果修改teacher_id,校验老师必须有效存在 + 3. 校验新组合(class_id+teacher_id+role)不能和其他有效记录重复 + """ + # 1. 查询原有记录 + db_rel = db.query(ClassTeachers).filter( + ClassTeachers.id == rel_id, + ClassTeachers.is_deleted == 0 + ).first() + if not db_rel: + return None + + # 2. 如果老师ID发生变化,校验老师是否有效 + if obj.teacher_id != db_rel.teacher_id: + teacher = get_teacher_by_id(db, obj.teacher_id) + if not teacher: + raise HTTPException(status_code=404, detail="老师不存在或已删除!") + + # 3. 查重:新的三元组合不能重复(排除自身这条记录) + exist_rel = db.query(ClassTeachers).filter( + ClassTeachers.class_id == obj.class_id, + ClassTeachers.teacher_id == obj.teacher_id, + ClassTeachers.role == obj.role, + ClassTeachers.is_deleted == 0, + ClassTeachers.id != rel_id + ).first() + if exist_rel: + raise HTTPException(status_code=409, detail="该老师已以相同角色分配到该班级!") + + # 赋值更新 + db_rel.class_id = obj.class_id + db_rel.teacher_id = obj.teacher_id + db_rel.role = obj.role + + db.commit() + db.refresh(db_rel) + return db_rel + + +#删除 +def delete_class_teacher(db: Session, rel_id: int): + """ + 逻辑删除班级老师带班关系 + :param db: Session + :param rel_id: class_teachers表主键id + :return: ClassTeacher ORM对象,找不到返回None + """ + db_obj = ( + db.query(ClassTeachers) + .filter(ClassTeachers.id == rel_id, ClassTeachers.is_deleted == 0) + .first() + ) + if not db_obj: + return None + + db_obj.is_deleted = 1 + db.commit() + return db_obj diff --git a/models/class_teacher.py b/models/class_teacher.py index e69de29..db97dfd 100644 --- a/models/class_teacher.py +++ b/models/class_teacher.py @@ -0,0 +1,52 @@ +from sqlalchemy import (Column, Integer, String, Text, + BigInteger,ForeignKey,VARCHAR,DateTime + ) +from sqlalchemy.dialects.mssql import TINYINT + +from core.database import Base +from datetime import datetime + +#班级老师关系表 class_teachers_info_detail 中间表 ORM 模型完整定义 +#字段包括id,class_id,teacher_id,role,created_at,updated_at,is_deleted +class ClassTeachers(Base): + __tablename__ = "class_teachers_info_detail" + id = Column( + BigInteger + ,primary_key=True + ,autoincrement=True + ,comment='关系') + class_id = Column( + BigInteger + ,ForeignKey('class_id') + ,nullable=False + ,comment='关联 class_id' + ) + teacher_id = Column( + BigInteger + ,ForeignKey('teacher_id') + ,nullable=False + ,comment='关联 teacher_id' + ) + role = Column( + VARCHAR(30) + ,nullable=False + ,comment='老师在班级中的角色:head_teacher班主任 / lecturer授课老师 / assistant助教' + ) + created_at = Column( + DateTime + ,nullable=False + ,default=datetime.now() + ,comment='创建时间' + ) + updated_at = Column( + DateTime + ,nullable=False + ,default=datetime.now() + ,comment='更新时间' + ) + is_deleted = Column( + TINYINT + ,nullable=False + ,default=0 + ,comment='逻辑删除' + ) diff --git a/models/teacher.py b/models/teacher.py index fe6ff57..bcfe6a0 100644 --- a/models/teacher.py +++ b/models/teacher.py @@ -62,48 +62,4 @@ class Teacher(Base): ) -#班级老师关系表 class_teachers_info_detail 中间表 ORM 模型完整定义 -#字段包括id,class_id,teacher_id,role,created_at,updated_at,is_deleted -class ClassTeachers(Base): - __tablename__ = "class_teachers_info_detail" - id = Column( - BigInteger - ,primary_key=True - ,autoincrement=True - ,comment='关系') - class_id = Column( - BigInteger - ,ForeignKey('class_id') - ,nullable=False - ,comment='关联 class_id' - ) - teacher_id = Column( - BigInteger - ,ForeignKey('teacher_id') - ,nullable=False - ,comment='关联 teacher_id' - ) - role = Column( - VARCHAR(30) - ,nullable=False - ,comment='老师在班级中的角色:head_teacher班主任 / lecturer授课老师 / assistant助教' - ) - created_at = Column( - DateTime - ,nullable=False - ,default=datetime.now() - ,comment='创建时间' - ) - updated_at = Column( - DateTime - ,nullable=False - ,default=datetime.now() - ,comment='更新时间' - ) - is_deleted = Column( - TINYINT - ,nullable=False - ,default=0 - ,comment='逻辑删除' - ) diff --git a/schemas/teacher.py b/schemas/teacher.py index 93cb1fb..6ecac07 100644 --- a/schemas/teacher.py +++ b/schemas/teacher.py @@ -1,10 +1,16 @@ from pydantic import BaseModel from typing import Optional from datetime import datetime + +from sqlalchemy import BigInteger +from sqlalchemy.dialects.mssql import TINYINT +from sqlalchemy.dialects.mysql import VARCHAR + + #===============老师表=================== #===============请求体模型================ class TeacherCreate(BaseModel): - teacher_no: Optional[str] = None + teacher_no: Optional[int] = None teacher_name: Optional[str] = None email: Optional[str] = None phone: Optional[str] = None @@ -17,3 +23,36 @@ class TeacherUpdate(BaseModel): phone: Optional[str] = None remark: Optional[str] = None +#================响应体================== +class TeacherOut(BaseModel): + id: int + teacher_no: str + teacher_name: str + phone: Optional[str] + email: Optional[str] + remark: Optional[str] + created_at: datetime + updated_at: datetime + is_deleted: int +#`orm_mode = True` 是 Pydantic v1 的配置项。开启之后,Pydantic 可以直接读取 SQLAlchemy +# 查询得到的 ORM 对象的属性,自动映射生成接口响应 JSON,不用手动把 ORM 对象转为字典。 +# 这个配置只用在响应体 Out 模型,新增和修改的请求模型不需要。 + class Config: + from_attributes=True + +#=====班级老师中间表 class_teachers ========= +class ClassTeachersCreate(BaseModel): + class_id: int + teacher_id: int + role: str +#=================响应体=================== +class ClassTeacherOut(BaseModel): + id: int + class_id: int + teacher_id: int + role: str + created_at: datetime + updated_at: datetime + is_deleted: int + class Config: + from_attributes=True -- 2.54.0 From a602dc9de1a782cabbc53819d8cb2025eefcb4dd Mon Sep 17 00:00:00 2001 From: wolin_zhangyi <1141397129@qq.com> Date: Mon, 21 Sep 2026 22:00:46 +0800 Subject: [PATCH 2/2] 1.teacher dao 2.teacher api --- api/teacher.py | 2 +- dao/teacher.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/teacher.py b/api/teacher.py index 19e5985..c300850 100644 --- a/api/teacher.py +++ b/api/teacher.py @@ -21,7 +21,7 @@ from dao.teacher import ( router = APIRouter(prefix="/teacher", tags=["老师管理模块"]) -#===========================老师表=============================== +#============================老师表=============================== @router.get("/list", response_model=List[TeacherOut]) def api_get_teacher_list(db: Session = Depends(get_db)): """ diff --git a/dao/teacher.py b/dao/teacher.py index 239c3d5..bef465c 100644 --- a/dao/teacher.py +++ b/dao/teacher.py @@ -9,7 +9,7 @@ from fastapi import HTTPException ''' 本文件内容为老师表与班级老师关系表的增删改查函数集合 ''' -#================老师表Teacher的CRUD================ +#=================老师表Teacher的CRUD================ #查询所有未被删除的老师 def get_teacher_list(db:Session, teacher_id:int): teacher = get_teacher_by_id(db, teacher_id) -- 2.54.0