Files
wo_chovy/api/student_api.py
2026-09-21 19:49:26 +08:00

201 lines
7.4 KiB
Python

"""
学生管理模块 - API 层(路由)
"""
from typing import List
from fastapi import APIRouter, Depends, HTTPException, Path
from sqlalchemy.orm import Session
from dao import student_dao
from dao.student_dao import search_student, BusinessException, DuplicateStudentNo, get_student, student_dict, create_student, update_student, delete_student
from database import get_db
from schema.student_schema import StudentQuery, StudentCreate, StudentUpdate, AgeQuery, workTimeResponse, \
failMoreResponse, countAvgOrderResponse, higherScoreResponse, ClassGenderFlatItem
router = APIRouter()
# 按性别统计人数
@router.get("/count_gender",summary="按性别统计人数",response_model=List[ClassGenderFlatItem])
def count_gender(db:Session =Depends(get_db)):
res=student_dao.get_class_gender(db)
return res
# 统计分数高于分数线的
@router.get("/count_score_higherScores/{score}",summary="统计高于分数线的人数",response_model=List[higherScoreResponse])
def higher_score(score: int,db:Session =Depends(get_db)):
res = student_dao.get_higher_score(db, score)
return res
# 统计每个学生就业时长
@router.get("/search_workTime",summary="统计每个学生就业时长",response_model=List[workTimeResponse])
def work_time(db:Session =Depends(get_db)):
res = student_dao.work_time(db)
return res
# 统计不及格次数大于指定次数
@router.get("/fail_more",summary="统计不及格次数大于指定次数",response_model=List[failMoreResponse])
def fail_more_api(fail_times:int,db:Session =Depends(get_db)):
res = student_dao.get_fail_more_than(db,fail_times)
return res
# 统计平均分,可以切换排序方式
@router.get("/count_avg",summary="统计平均分,可以切换排序方式",response_model=List[countAvgOrderResponse])
def count_avg_api(order_type:str,db:Session =Depends(get_db)):
res = student_dao.count_avg(db,order_type)
return res
# 按年龄区间自定义比较
@router.post("/order_age",summary="按年龄区间自定义比较")
def get_students_by_age(query:AgeQuery,db:Session =Depends(get_db)):
res = student_dao.get_students_by_age(db,query)
return res
# 按就业信息排名查询学生
@router.get("get_top_salary",summary="按就业信息排名查询学生")
def get_top_n_salary(rank:int,db:Session =Depends(get_db)):
res = student_dao.get_top_n_salary(db,rank)
return res
# 统计每个班级的平均就业时长
@router.get("avg_work_time_by_class",summary="统计每个班级的平均就业时长")
def avg_work_time_by_class(db:Session =Depends(get_db)):
res = student_dao.avg_work_time_by_class(db)
return res
# ====================查询学生=====================
@router.get("/api/get/student",summary="模糊查询学生")
def list_student_api(
student_query: StudentQuery = Depends(),
db: Session = Depends(get_db),
):
"""
支持按学号、姓名(模糊)、班级筛选,分页返回。
请求示例:GET /api/student/?student_name=张&page=1&size=10
"""
try:
return search_student(
db,
student_no=student_query.student_no,
student_name=student_query.student_name,
class_id=student_query.class_id,
page=student_query.page,
size=student_query.size,
)
except BusinessException as e:
raise HTTPException(status_code=500, detail=str(e))
# ====================查询学生详情====================
@router.get("/get/student/{sid}", summary="查询学生详情")
def get_student_api(
sid: int = Path(..., ge=1, description="学生ID"),
db: Session = Depends(get_db),
):
try:
student = get_student(db, sid)
if student is None:
raise HTTPException(status_code=404, detail=f"学生 {sid} 不存在")
return student_dict(student)
except BusinessException as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 2. 创建学生 ====================
@router.post("/api/create/student")
def create_student_api(
student_create:StudentCreate, # 不加 Depends -> 走 JSON 请求体
db: Session = Depends(get_db),
):
"""
请求体:测试数据
{
"student_no": "S2023011",
"student_name": "李四",
"class_id": 1,
"flag": 1,
"advisor_id": 1,
"native_place": "江苏南京",
"school": "东南大学",
"major": "软件工程",
"enrollment_time": "2023-09-01",
"graduation_time": "2026-06-30",
"education": "本科",
"age": 20,
"gender": "男",
"state": "在读"
}
"""
try:
student = create_student(
db,
student_no=student_create.student_no,
student_name=student_create.student_name,
class_id=student_create.class_id,
flag=student_create.flag,
advisor_id=student_create.advisor_id,
native_place=student_create.native_place,
school=student_create.school,
major=student_create.major,
enrollment_time=student_create.enrollment_time,
graduation_time=student_create.graduation_time,
education=student_create.education,
age=student_create.age,
gender=student_create.gender,
state=student_create.state,
)
return {"message": "创建成功", "data": student_dict(student)}
except DuplicateStudentNo as e:
raise HTTPException(status_code=409, detail=str(e))
except BusinessException as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 3. 更新学生 ====================
@router.put("/api/update/student/{sid}", summary="更新学生")
def update_student_api(
params: StudentUpdate,
sid: int = Path(..., ge=1, description="学生ID"),
db: Session = Depends(get_db),
):
"""
学号不在更新范围内(业务主键不可改)。
"""
try:
student = update_student(
db,
sid=sid,
student_name=params.student_name,
class_id=params.class_id,
flag=params.flag,
advisor_id=params.advisor_id,
native_place=params.native_place,
school=params.school,
major=params.major,
enrollment_time=params.enrollment_time,
graduation_time=params.graduation_time,
education=params.education,
age=params.age,
gender=params.gender,
state=params.state,
)
if student is None:
raise HTTPException(status_code=404, detail=f"学生 {sid} 不存在")
return {"message": "更新成功", "data": student_dict(student)}
except BusinessException as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 4. 删除学生(逻辑删除) ====================
@router.delete("/api/delete/student/{sid}", summary="删除学生(逻辑删除)")
def delete_student_api(
sid: int = Path(..., ge=1, description="学生ID"),
db: Session = Depends(get_db),
):
"""逻辑删除:把 flag 置 0,数据行仍然保留。"""
try:
student = delete_student(db, sid)
if student is None:
raise HTTPException(status_code=404, detail=f"学生 {sid} 不存在或已删除")
return {"message": f"学生 {student.student_name} 删除成功"}
except BusinessException as e:
raise HTTPException(status_code=500, detail=str(e))