Zhangyi #29

Merged
lookerZz merged 3 commits from zhangyi into main 2026-09-21 22:02:32 +08:00
3 changed files with 408 additions and 1 deletions
+129
View File
@@ -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": "解除班级带班关系成功"}
+239
View File
@@ -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
+40 -1
View File
@@ -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