Merge pull request 'Zhangyi' (#29) from zhangyi into main
Reviewed-on: #29
This commit was merged in pull request #29.
This commit is contained in:
+129
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user