commit 70783dd3500ed24206c9d8c64793323fc9aade63 Author: mister-ye <17608588+yewenwei2002@user.noreply.gitee.com> Date: Mon Sep 21 18:03:04 2026 +0800 feat: 初始化学生管理系统代码 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b6b1ecf --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 已忽略包含查询文件的默认文件夹 +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7e7ac73 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..9de2865 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..6e86413 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/沃林学生管理系统.iml b/.idea/沃林学生管理系统.iml new file mode 100644 index 0000000..8437fe6 --- /dev/null +++ b/.idea/沃林学生管理系统.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/advisor_api.py b/api/advisor_api.py new file mode 100644 index 0000000..f989887 --- /dev/null +++ b/api/advisor_api.py @@ -0,0 +1,60 @@ +from fastapi import APIRouter, Depends, HTTPException, Query +from sqlalchemy.orm import Session +from dao import advisor_dao +from database import get_db +from scheme.advisor_scheme import ( + AdvisorCreate, + AdvisorResp, + AdvisorStudentResp, + AdvisorUpdate, +) + +# router = APIRouter(prefix="/advisor", tags=["顾问管理模块"]) +router = APIRouter() + +@router.post("/", response_model=AdvisorResp, summary="新增顾问") +def add_advisor(advisor: AdvisorCreate, db: Session = Depends(get_db)): + if advisor_dao.get_advisor_by_no(db, advisor.advisor_no): + raise HTTPException(status_code=400, detail=f"顾问编号 {advisor.advisor_no} 已存在") + return advisor_dao.create_advisor(db, advisor) + +@router.get("/", response_model=list[AdvisorResp], summary="顾问列表/搜索") +def get_advisor_list( + search_keyword: str | None = Query(default=None, description="按顾问编号或姓名模糊搜索"), + db: Session = Depends(get_db), +): + return advisor_dao.get_advisor_list(db, search_keyword) + + + +@router.get("/{advisor_no}", response_model=AdvisorResp, summary="按编号查询顾问") +def get_advisor(advisor_no: str, db: Session = Depends(get_db)): + advisor = advisor_dao.get_advisor_by_no(db, advisor_no) + if not advisor: + raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在") + return advisor + + +# 查该顾问名下所有学生 +@router.get("/{advisor_no}/students", response_model=list[AdvisorStudentResp], summary="查询顾问名下学生") +def get_advisor_students(advisor_no: str, db: Session = Depends(get_db)): + if not advisor_dao.get_advisor_by_no(db, advisor_no): + raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在") + return advisor_dao.get_students_by_advisor_no(db, advisor_no) + + +@router.put("/{advisor_no}", response_model=AdvisorResp, summary="更新顾问") +def update_advisor(advisor_no: str, update: AdvisorUpdate, db: Session = Depends(get_db)): + advisor = advisor_dao.update_advisor(db, advisor_no, update.model_dump(exclude_unset=True)) + if not advisor: + raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在") + return advisor + +# 请求:DELETE /advisor/A001 +@router.delete("/{advisor_no}", response_model=AdvisorResp, summary="删除顾问") +def delete_advisor(advisor_no: str, db: Session = Depends(get_db)): + advisor = advisor_dao.delete_advisor(db, advisor_no) + if not advisor: + raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在") + return advisor + diff --git a/api/api_analysis.py b/api/api_analysis.py new file mode 100644 index 0000000..b4baa45 --- /dev/null +++ b/api/api_analysis.py @@ -0,0 +1,90 @@ +from fastapi import APIRouter, Query, Depends +from sqlalchemy.orm import Session + +from dao.age_analysis import ( + analysis_student_age, + analysis_class_gender, + analysis_score_over, + analysis_score_not_qualified, + analysis_avg_score_order, + analysis_employment_salary_order, + analysis_student_employment_time, + avg_employment_time, +) +from database import get_db +from scheme.schema_analysis import ( + StudentOut, + StudentGenderOut, + StudentRecordOut1, + StudentRecordOut2, + StudentRecordOut3, + StudentRecordOut4, + StudentRecordOut5, + StudentRecordOut6, +) + +router = APIRouter() + + +# 动态年龄范围查询:支持输入年龄阈值(大于等于/小于等于)动态查询学员信息 +@router.get("/analysis_age", response_model=list[StudentOut]) +async def analysis_age( + db: Session = Depends(get_db), + min_age: int | None = Query(None, ge=0, description="请输入查询年龄大于等于"), + max_age: int | None = Query(None, ge=0, description="请输入查询年龄小于等于"), +): + return analysis_student_age(db, min_age, max_age) + + +# 统计每个班级的总人数,以及按性别(男、女)细分的人数分布 +@router.get("/analysis_gender", response_model=list[StudentGenderOut]) +async def analysis_gender(db: Session = Depends(get_db)): + return analysis_class_gender(db) + + +# 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩 +@router.get("/analysis_scores", response_model=list[StudentRecordOut1]) +async def analysis_scores( + db: Session = Depends(get_db), + score: float = Query(0, ge=0, le=100, description="请输入查询学生每次考试分数在多少以上"), +): + return analysis_score_over(db, score) + + +# 查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细 +@router.get("/analysis_not_qualified", response_model=list[StudentRecordOut2]) +async def analysis_not_qualified( + db: Session = Depends(get_db), + n: int = Query(1, ge=1, description="请输入不及格次数下限"), +): + return analysis_score_not_qualified(db, n) + + +# 统计每次考试每个班级的平均分,支持按分数从高到低或从低到高动态排序 +@router.get("/analysis_avg_score", response_model=list[StudentRecordOut3]) +async def analysis_avg_score( + db: Session = Depends(get_db), + sort: str = Query("asc", description="请输入排序类型 asc/desc"), +): + return analysis_avg_score_order(db, sort) + + +# 统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司 +@router.get("/analysis_salary_top", response_model=list[StudentRecordOut4]) +async def analysis_salary_top( + db: Session = Depends(get_db), + n: int = Query(1, ge=1, description="请输入取前几名薪资"), +): + return analysis_employment_salary_order(db, n) + + +# 统计每个学生的就业时长(offer下发时间 - 就业开放时间,单位秒) +@router.get("/analysis_employment_time", response_model=list[StudentRecordOut5]) +async def analysis_employment_time(db: Session = Depends(get_db)): + return analysis_student_employment_time(db) + + +# 统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生) +@router.get("/analysis_avg_employment_time", response_model=list[StudentRecordOut6]) +async def analysis_avg_employment_time(db: Session = Depends(get_db)): + return avg_employment_time(db) diff --git a/api/classinfo_api.py b/api/classinfo_api.py new file mode 100644 index 0000000..890e371 --- /dev/null +++ b/api/classinfo_api.py @@ -0,0 +1,45 @@ +# 路由接口 +from typing import List + +from fastapi import APIRouter,Depends,HTTPException +from sqlalchemy.orm import Session + +from database import get_db +from dao.classinfo_dao import create_class,get_class,get_all_class,update_class,delete_class +from scheme.classinfo_scheme import ClassCreate,ClassUpdate,ClassIn + + +router=APIRouter() +# 新增班级 +@router.post("/",response_model=ClassIn) +def add_class(class_data:ClassCreate,db:Session=Depends(get_db)): + return create_class(db=db,obj=class_data) + +# 条件查询(id / 名称筛选) +@router.get("/search",response_model=List[ClassIn]) +def get_cls(class_id:int=None,class_name:str=None,db:Session=Depends(get_db)): + res_list=get_class(db=db,class_id=class_id,class_name=class_name) + if not res_list: + raise HTTPException(status_code=404,detail="班级不存在") + return res_list + +# 查询全部有效班级 +@router.get("/",response_model=List[ClassIn]) +def get_all(db:Session=Depends(get_db)): + return get_all_class(db=db) + +# 修改班级 +@router.put("/{class_id}",response_model=ClassIn) +def up_class(class_id:int,class_data:ClassUpdate,db:Session=Depends(get_db)): + res=update_class(db=db,class_id=class_id,obj=class_data) + if not res: + raise HTTPException(status_code=404,detail="班级不存在") + return res + +# 逻辑删除 +@router.delete("/{class_id}") +def del_class(class_id:int,db:Session=Depends(get_db)): + res=delete_class(db=db,class_id=class_id) + if not res: + raise HTTPException(status_code=404,detail="班级不存在") + return {"msg":"逻辑删除成功"} diff --git a/api/employment_api.py b/api/employment_api.py new file mode 100644 index 0000000..4656041 --- /dev/null +++ b/api/employment_api.py @@ -0,0 +1,114 @@ +from fastapi import APIRouter, HTTPException, Depends, Query +from sqlalchemy import and_ +from sqlalchemy.orm import Session +from model.employment import Employment + +from dao import employment_dao +from database import get_db +from model.student import Student +# from model.student import Student +from scheme.employment_scheme import EmploymentOut, EmploymentCreate + +router=APIRouter() + +def stu_id(db:Session,stu_id:int): + student=(db.query(Student).filter(Student.id==stu_id,Student.statu==1).first()) + if not student: + raise HTTPException(status_code=404,detail="该学生不存在") + return student +@router.get("/",response_model=list[EmploymentOut]) +def set_employment( + stu_id:int = None, + name:str = None, + min_salary: float = None, + max_salary: float = None, + db:Session = Depends(get_db), +): + obj=employment_dao.set_employment(db + ,stu_id + ,name + ,min_salary + ,max_salary) + emp_list=[] + for i in obj: + data={ + "id":i.id, + "stu_id":i.stu_id, + "name":i.name, + "employment_open_time":i.employment_open_time, + "offer_time":i.offer_time, + "salary":i.salary + } + emp_list.append(data) + return emp_list +@router.post("/",response_model=EmploymentCreate) +def update_emp( + stu_id:int = Query(...,description="学生ID"), + data:EmploymentCreate=None, + db:Session=Depends(get_db) +): + student=(db.query(Student).filter(and_(Student.id==stu_id,Student.statu==1)).first()) + if not student: + raise HTTPException(status_code=404,detail="该学生不存在") + try: + obj=employment_dao.update_employment(db,stu_id,data) + except ValueError as e: + raise HTTPException(status_code=400,detail=str(e)) + emp_dict={ + "id":obj.id, + "stu_id":obj.stu_id, + "name":obj.name, + "employment_open_time":obj.employment_open_time, + "offer_time":obj.offer_time, + "salary":obj.salary + } + return emp_dict +@router.post("/create", response_model=EmploymentOut) +def create_employment( + stu_id: int = Query(..., description="学生ID"), + data: EmploymentCreate = None, + db: Session = Depends(get_db), +): + student = ( + db.query(Student) + .filter(and_(Student.id == stu_id, Student.statu == 1)) + .first() + ) + if not student: + raise HTTPException(status_code=404, detail="该学生不存在") + exist = employment_dao.get_by_stu_id(db, stu_id) + if exist: + raise HTTPException(status_code=400, detail="该学生已存在就业信息,请使用更新接口") + open_time = data.employment_open_time + offer_time = data.offer_time + if open_time is not None and offer_time is not None: + if offer_time < open_time: + raise HTTPException(status_code=400, detail="offer下发时间必须晚于就业开放时间") + obj = Employment() + obj.stu_id = stu_id + obj.name = data.name + obj.employment_open_time = open_time + obj.offer_time = offer_time + obj.company_name = data.company_name + obj.salary = data.salary + db.add(obj) + db.commit() + db.refresh(obj) + emp_dict = { + "id": obj.id, + "stu_id": obj.stu_id, + "name": obj.name, + "employment_open_time": obj.employment_open_time, + "offer_time": obj.offer_time, + "salary": obj.salary, + } + return emp_dict + +@router.delete("/") +def delete_emp(emp_id:int,db:Session = Depends(get_db)): + del_emp=employment_dao.delete_emp(db,emp_id) + if not del_emp: + raise HTTPException(status_code=404,detail="该就业信息不存在") + return {"code":0,"message":"删除成功"} + + diff --git a/api/score_api.py b/api/score_api.py new file mode 100644 index 0000000..5c85587 --- /dev/null +++ b/api/score_api.py @@ -0,0 +1,75 @@ +# api/score.py +from fastapi import APIRouter, Depends, HTTPException, Query +from sqlalchemy.orm import Session +from dao import score_dao +from database import get_db + +# 创建路由器 +router = APIRouter() + + + +# 不及格学生表 + +@router.get("/warning/list") +async def warning_list(db: Session = Depends(get_db)): + return score_dao.get_warning(db) + + + +# 查某学生所有成绩 + + +@router.get("/{stu_id}") +def get_scores(stu_id: int, db: Session = Depends(get_db)): + return score_dao.get_score(db, stu_id) + + +# 增 + +@router.post("/") +def add_score( + student_id: int = Query(...), + exam_seq: int = Query(...), + score: float = Query(...), + db: Session = Depends(get_db), +): + obj, err = score_dao.add_score(db, student_id, exam_seq, score) + if err: + raise HTTPException(status_code=400, detail=err) + return obj + + + + +# 改 + + +@router.put("/update") +def update_score( + student_id: int = Query(...), + exam_seq: int = Query(...), + score: float = Query(...), + db: Session = Depends(get_db), +): + obj, err = score_dao.update_score(db, student_id, exam_seq, score) + if err: + raise HTTPException(status_code=404, detail=err) + return obj + + +# 逻辑删除 + + +@router.post("/delete") +def delete_score( + student_id: int = Query(...), + exam_seq: int = Query(...), + db: Session = Depends(get_db), +): + obj, err = score_dao.delete_score(db, student_id, exam_seq) + if err: + raise HTTPException(status_code=404, detail=err) + return {"message": "已删除,数据仍保留在后台"} + + diff --git a/api/student_api.py b/api/student_api.py new file mode 100644 index 0000000..00d9294 --- /dev/null +++ b/api/student_api.py @@ -0,0 +1,41 @@ +from typing import Optional +from fastapi import APIRouter, HTTPException,Depends,Query +from sqlalchemy.orm import Session +from dao import student_dao +from database import get_db +from scheme.student_scheme import Create_Stu_Mod + +# 创建路由器 +router = APIRouter() + +@router.get("/") +async def get_students(db: Session = Depends(get_db)): + # 把db作为参数传给dao函数 + return student_dao.get_stu(db) + +@router.get("/all_stu") +def get_all_stu(db: Session = Depends(get_db)): + return student_dao.get_all_stu(db) + +@router.get("/stu_id") +def get_sid(stu_id:Optional[int]=Query(None,gt=0,description="输入学生编号精确查找"), + class_id:Optional[int]=Query(None,description="同时输入班级和姓名进行查找"), + stu_name:Optional[str]=Query(None,description="同时输入班级和姓名进行查找"), + db:Session=Depends(get_db)): + if stu_id is not None: + return student_dao.query_sid(db,stu_id) + elif class_id is not None and stu_name is not None: + return student_dao.query_cid(db,class_id,stu_name) + return {"message":""} + +@router.get("/delete/{stu_id}") +def delete_sid(stu_id:int,db:Session = Depends(get_db)): + return student_dao.delete_sid(db,stu_id) +#新增学生 +@router.post("/create_stu") +def create_stu(stu:Create_Stu_Mod,db:Session = Depends(get_db)): + return student_dao.create_stu(db,stu) +# 修改学生 +@router.post("/update_stu/{stu_id}") +def update_stu(stu_id:int,stu:Create_Stu_Mod,db:Session = Depends(get_db)): + return student_dao.update_stu(stu_id,stu,db) diff --git a/api/teacher_api.py b/api/teacher_api.py new file mode 100644 index 0000000..d382c9b --- /dev/null +++ b/api/teacher_api.py @@ -0,0 +1,55 @@ +# api/teacher.py +# 本文件定义教师相关的所有 API 路由(Controller 层) +# dao/users_dao.py +# 本文件封装对 Teacher表的所有数据库操作(增、删、改、查) +# api/teacher.py +# 本文件定义教师相关的所有 API 路由(Controller 层) +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from scheme.teacher_scheme import TeacherCreate, TeacherUpdate +from dao.teacher_dao import add_teacher, get_teacher_by_id, delete_teacher_logic, update_teacher_logic +from database import get_db + +#创建路由 +router=APIRouter() + +#新增老师 POST +@router.post("/") +def create_teacher(teacher_in: TeacherCreate, db: Session = Depends(get_db)): + return add_teacher(db, teacher_in.teacher_no, teacher_in.name, teacher_in.phone) + +#根据id查询老师 GET +@router.get("/{teacher_id}") +def get_one_teacher(teacher_id: int, db: Session = Depends(get_db)): + teacher = get_teacher_by_id(db, teacher_id) + if not teacher: + raise HTTPException(status_code=404, detail="老师不存在") + return { + "id": teacher.id, + "teacher_no": teacher.teacher_no, + "name": teacher.name, + "phone": teacher.phone + } + +#修改老师 PUT +@router.put("/{teacher_id}") +def update_teacher(teacher_id: int, teacher_in: TeacherUpdate, db: Session = Depends(get_db)): + teacher = update_teacher_logic(db, teacher_id, teacher_in.name, teacher_in.phone) + if not teacher: + raise HTTPException(status_code=404, detail="老师不存在") + return { + "id": teacher.id, + "teacher_no": teacher.teacher_no, + "name": teacher.name, + "phone": teacher.phone + } + +#删除老师 DELETE(逻辑删除) +@router.delete("/{teacher_id}") +def delete_teacher(teacher_id: int, db: Session = Depends(get_db)): + teacher = delete_teacher_logic(db, teacher_id) + if not teacher: + return {"success": False, "msg": "数据不存在"} + return {"success": True, "msg": "删除成功"} + + diff --git a/dao/__init__.py b/dao/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dao/advisor_dao.py b/dao/advisor_dao.py new file mode 100644 index 0000000..126169e --- /dev/null +++ b/dao/advisor_dao.py @@ -0,0 +1,69 @@ +from sqlalchemy import and_, or_ +from sqlalchemy.orm import Session +from model.advisor import Advisor +from model.student import Student +from scheme.advisor_scheme import AdvisorCreate +# 新增顾问信息(前端传过来的、且已经 scheme 校验好的数据) + +def create_advisor(db: Session, advisor: AdvisorCreate) -> Advisor: + db_advisor = Advisor( + advisor_no=advisor.advisor_no, + name=advisor.name, + gender=advisor.gender, + phone=advisor.phone, + remark=advisor.remark, + ) + db.add(db_advisor) + db.commit() + db.refresh(db_advisor) + return db_advisor + +# 顾问信息查询:支持全部查询 / 模糊搜索(匹配顾问编号、姓名) +def get_advisor_list(db: Session, search_keyword: str = None): + q = db.query(Advisor).filter(Advisor.statu == 1) + if search_keyword: + q = q.filter( + or_( + Advisor.advisor_no.like(f"%{search_keyword}%"), + Advisor.name.like(f"%{search_keyword}%"), + ) + ) + return q.all() + + +# 根据顾问编号查询单个存在的顾问 +def get_advisor_by_no(db: Session, advisor_no: str): + return ( + db.query(Advisor) + .filter(and_(Advisor.advisor_no == advisor_no, Advisor.statu == 1)) + .first() + ) + +# 查询该顾问名下所有学生 +def get_students_by_advisor_no(db: Session, advisor_no: str): + return ( + db.query(Student) + .filter(and_(Student.advisor_no == advisor_no, Student.statu == 1)) + .all() + ) + +# 更新顾问信息(setattr(obj, "k", "v") 动态赋值) +def update_advisor(db: Session, advisor_no: str, update_data: dict): + advisor = get_advisor_by_no(db, advisor_no) + if not advisor: + return None + update_data.pop("advisor_no", None) + for k, v in update_data.items(): + setattr(advisor, k, v) + db.commit() + db.refresh(advisor) + return advisor + +# 删除顾问:逻辑删除 +def delete_advisor(db: Session, advisor_no: str): + advisor = get_advisor_by_no(db, advisor_no) + if not advisor: + return None + advisor.statu = 0 + db.commit() + return advisor diff --git a/dao/age_analysis.py b/dao/age_analysis.py new file mode 100644 index 0000000..33bf92a --- /dev/null +++ b/dao/age_analysis.py @@ -0,0 +1,135 @@ +from fastapi import HTTPException + +from model.classinfo import ClassInfo +from model.employment import Employment +from model.score import Score +from model.student import Student +from sqlalchemy.orm import Session + +from sqlalchemy import case, func, text, and_ + + +def analysis_student_age(db: Session, min_age: int | None = None, max_age: int | None = None): + #按年龄区间(>=min 且 <=max)查询学生,区间可缺省。 + if min_age is not None and min_age < 0: + raise HTTPException(status_code=400, detail="最小年龄不能小于0") + elif min_age is not None and max_age is not None and min_age > max_age: + raise HTTPException(status_code=400, detail="最小年龄不能大于最大年龄") + elif min_age is None and max_age is None : + data_age= db.query(Student).all() + elif min_age is not None and max_age is None: + data_age = db.query(Student).filter(Student.age >= min_age).all() + elif max_age is not None and min_age is None: + data_age = db.query(Student).filter(Student.age <= max_age).all() + elif min_age is not None and max_age is not None: + data_age = db.query(Student).filter(and_(Student.age >= min_age, Student.age <= max_age)).all() + return data_age + + +def analysis_class_gender(db: Session): + #每个班级总人数及男、女人数。 + data= (db.query( + Student.class_id, + func.count(Student.id).label("total"), + func.sum(case((Student.gender == "男", 1), else_=0)).label("gender_male"), + func.sum(case((Student.gender == "女", 1), else_=0)).label("gender_female"), + ).group_by(Student.class_id).all()) + return data + +def analysis_score_over(db: Session, score_over: float = 0): + #每次考试成绩都在分数线以上的学生的编号、姓名和成绩。 + qualified_student_ids = ( + db.query(Score.student_id) + .group_by(Score.student_id) + .having(func.min(Score.score) >= score_over) + ) + data=( + db.query(Student.id, Student.name, Score.score) + .join(Score, Student.id == Score.student_id) + .filter(Student.id.in_(qualified_student_ids)) + .all() + ) + return data + +def analysis_score_not_qualified(db: Session, not_qualified_count: int = 1): + #有指定次数以上不及格(<60)的学生的姓名、班级和不及格成绩明细。 + not_qualified_students = (db.query(Score.student_id) + .filter(Score.score < 60) + .group_by(Score.student_id) + .having(func.count(Score.student_id) >= not_qualified_count)) + data=(db.query(Student.id, Student.name, Student.class_id, Score.score) + .join(Score, Student.id == Score.student_id) + .filter(Student.id.in_(not_qualified_students), Score.score < 60).all()) + return data + + +def analysis_avg_score_order(db: Session, sort_type: str = "asc"): + #每次考试每个班级的平均分,asc/desc 排序。 + if sort_type not in ("asc", "desc"): + raise HTTPException(status_code=400, detail="sort 参数只能为 asc 或 desc") + avg_score = func.avg(Score.score).label("avg_score") + query = ( + db.query(Score.exam_seq, ClassInfo.class_name, avg_score) + .join(Student, Score.student_id == Student.id) + .join(ClassInfo, Student.class_id == ClassInfo.id) + .group_by(Score.exam_seq, ClassInfo.class_name) + ) + if sort_type == "asc": + data = query.order_by(avg_score.asc()).all() + else: + data = query.order_by(avg_score.desc()).all() + return data + + +def analysis_employment_salary_order(db: Session, n: int = 1): + #就业薪资排名 Top N 的学生姓名、班级、就业时间和就业公司 + data=(db.query( + Student.name, + Student.class_id, + Employment.employment_open_time, + Employment.company_name, + Employment.salary) + .join(Employment, Employment.stu_id == Student.id) + .order_by(Employment.salary.desc()).limit(n).all()) + return data + +def analysis_student_employment_time(db: Session): + #每个学生的就业时长(offer下发时间 - 就业开放时间,单位秒)。 + data=( + db.query( + Employment.stu_id, + func.timestampdiff( + text("SECOND"), + Employment.employment_open_time, + Employment.offer_time, + ).label("time_diff"), + ) + .filter( + Employment.employment_open_time.isnot(None), + Employment.offer_time.isnot(None), + ) + .all() + ) + return data + +def avg_employment_time(db: Session): + #每个班级的平均就业时长(仅统计有就业开放时间的学生,单位秒) + return ( + db.query( + Student.class_id, + func.avg( + func.timestampdiff( + text("SECOND"), + Employment.employment_open_time, + Employment.offer_time, + ) + ).label("time_diff"), + ) + .join(Employment, Employment.stu_id == Student.id) + .filter( + Employment.employment_open_time.isnot(None), + Employment.offer_time.isnot(None), + ) + .group_by(Student.class_id) + .all() + ) diff --git a/dao/classinfo_dao.py b/dao/classinfo_dao.py new file mode 100644 index 0000000..0c8a8dd --- /dev/null +++ b/dao/classinfo_dao.py @@ -0,0 +1,45 @@ +from model.classinfo import ClassInfo +from scheme.classinfo_scheme import ClassCreate, ClassUpdate + +# 增删改查 +def create_class(db,obj:ClassCreate): + new_class=ClassInfo(class_name=obj.class_name,start_time=obj.start_time,statu=1) + db.add(new_class) + db.commit() + db.refresh(new_class) + return new_class +# 查询单个班级 +def get_class(db,class_id=None,class_name=None): + u1=db.query(ClassInfo).filter(ClassInfo.statu==1) + if class_id is not None: + u1=u1.filter(ClassInfo.id==class_id) + if class_name is not None: + u1=u1.filter(ClassInfo.class_name.like(f"%{class_name}%")) + if class_id is not None: + return u1.first() + else: + return u1.all() +# 查询所有班级 +def get_all_class(db): + return db.query(ClassInfo).filter(ClassInfo.statu==1).all() +# 修改班级` +def update_class(db,class_id:int,obj:ClassUpdate): + u2=get_class(db,class_id) + if u2: + u2.class_name=obj.class_name + u2.start_time=obj.start_time + db.commit() + db.refresh(u2) + return u2 + else: + return None +# 删除班级 +def delete_class(db,class_id:int): + u3=get_class(db,class_id) + if u3: + u3.statu=0 + db.commit() + db.refresh(u3) + return u3 + else: + return None diff --git a/dao/employment_dao.py b/dao/employment_dao.py new file mode 100644 index 0000000..5b9a27b --- /dev/null +++ b/dao/employment_dao.py @@ -0,0 +1,86 @@ +from sqlalchemy import and_ +from sqlalchemy.orm import Session + +from scheme import employment_scheme +from scheme.employment_scheme import EmploymentCreate +from model.employment import Employment +from model.student import Student + +def update_employment(db:Session,stu_id:int,data:employment_scheme.EmploymentCreate): + obj=get_by_stu_id(db,stu_id) + open_time=data.employment_open_time + offer_time=data.offer_time + if open_time is not None and offer_time is not None : + if offer_time< open_time: + raise ValueError("offer下发时间必须晚于及就业开放时间") + emp_dict={ + "stu_id":stu_id, + "name":data.name, + "employment_open_time":open_time, + "offer_time":offer_time, + "company_name":data.company_name, + "salary":data.salary + } + if obj: + obj.stu_id = stu_id + obj.name = data.name + obj.employment_open_time = open_time + obj.offer_time = offer_time + obj.company_name = data.company_name + obj.salary = data.salary + else: + obj = Employment() + obj.stu_id = stu_id + obj.employment_open_time = open_time + obj.offer_time = offer_time + obj.company_name = data.company_name + obj.salary = data.salary + db.add(obj) + db.commit() + db.refresh(obj) + return obj +def get_employment(db:Session,emp_id: int): + employment= (db.query(Employment).filter(Employment.id == emp_id, Employment.is_deleted == False).first()) + return employment +def get_by_stu_id(db:Session,stu_id:int): + employment=(db.query(Employment).filter(Employment.stu_id == stu_id, Employment.is_deleted == 0).first()) + return employment +def set_employment(db:Session, + stu_id: int = None, + name: str = None, + min_salary: float = None, + max_salary: float = None): + s=db.query(Employment).filter(Employment.is_deleted == False) + if stu_id is not None: + s = s.filter(Employment.stu_id == stu_id) + if name is not None: + s = s.filter(Employment.name.like(f'%{name}%')) + if min_salary is not None: + s = s.filter(Employment.salary >= min_salary) + if max_salary is not None: + s = s.filter(Employment.salary <= max_salary) + return s +def create_employment(db: Session, stu_id: int, data: EmploymentCreate): + obj = Employment() + obj.stu_id = stu_id + obj.name = data.name + obj.employment_open_time = data.employment_open_time + obj.offer_time = data.offer_time + obj.company_name = data.company_name + obj.salary = data.salary + db.add(obj) + db.commit() + return obj +def delete_emp(db:Session,emp_id:int): + obj=get_employment(db,emp_id) + if not obj: + return False + obj.is_deleted=1 + db.commit() + return True + + + + + + diff --git a/dao/score_dao.py b/dao/score_dao.py new file mode 100644 index 0000000..8a7cbc3 --- /dev/null +++ b/dao/score_dao.py @@ -0,0 +1,115 @@ +# dao/score_dao.py +from sqlalchemy.orm import Session +from model.score import Score +from model.student import Student + + + # 查 +# 查一个学生所有成绩 + +def get_score(db: Session, student_id: int): + return db.query(Score).filter( + Score.student_id == student_id, + Score.is_deleted == 0, + ).order_by(Score.exam_seq.asc()).all() + + + +# 查某学生的某次成绩 +def get_one_score(db: Session, student_id: int, exam_seq: int): + + return db.query(Score).filter( + Score.student_id == student_id, + Score.exam_seq == exam_seq, + Score.is_deleted == 0, + ).first() + + + +# 查不及格的 +def get_warning(db: Session): + return db.query(Score).filter( + Score.is_warning == 1, + Score.is_deleted == 0, + ).all() + + + + + + +# 录 + + +# 录信息 +def add_score(db: Session, student_id: int, exam_seq: int, score: float): + + stu = db.query(Student).filter(Student.id == student_id).first() + if not stu: + return None, "学生不存在" + + + exists = get_one_score(db, student_id, exam_seq) + if exists: + return None, "该学生这次成绩已录过" + + + + new_score = Score( + student_id=student_id, + exam_seq=exam_seq, + score=score, + is_warning=1 if score < 60 else 0, + is_deleted=0, + ) + db.add(new_score) + db.commit() + db.refresh(new_score) + return new_score, None + + + + + +# 改 + + # 改成绩 + +def update_score(db: Session, student_id: int, exam_seq: int, new_score: float): + + + obj = get_one_score(db, student_id, exam_seq) + if not obj: + return None, "成绩不存在或已删除" + + obj.score = new_score + + # 如果不及格 预警重置 + obj.is_warning = 1 if new_score < 60 else 0 + + db.commit() + db.refresh(obj) + return obj, None + + + + + +# 逻辑删除 + + +def delete_score(db: Session, student_id: int, exam_seq: int): + # 把删除的学生0改成1 + + obj = get_one_score(db, student_id, exam_seq) + + if not obj: + return None, "成绩不存在或已删除" + + + # 0 → 1 + obj.is_deleted = 1 + db.commit() + return obj, None + + diff --git a/dao/student_dao.py b/dao/student_dao.py new file mode 100644 index 0000000..cd37b22 --- /dev/null +++ b/dao/student_dao.py @@ -0,0 +1,109 @@ +from fastapi import HTTPException +from sqlalchemy import and_ +from sqlalchemy.orm import Session +from model.advisor import Advisor +from model.student import Student +from model.classinfo import ClassInfo +from datetime import date +import scheme +import api + +def get_stu(db:Session): + res=db.query(Student).all() + l1=list() + for i in res : + l1.append(i.name) + return {"message":l1} + +def get_all_stu(db:Session): + rs=db.query(Student).filter(Student.statu==1).all() + return {"message":"查询成功","data":rs} + +def get_stu_id(stu_id:int,db:Session): + res = db.query(Student).filter(Student.id==stu_id).all() + l1 = list() + for i in res: + l1.append(i.name) + return {"message": l1} + +def query_sid(db:Session,stu_id): + res=db.query(Student).filter(Student.id==stu_id).first() + return res +#按班级姓名查 +def query_cid(db:Session,class_id,stu_name): + res=db.query(Student).filter(and_(Student.class_id==class_id,Student.name==stu_name)).first() + return {"data":res} + +def query_stu_name(db:Session,stu_name): + res=db.query(Student).filter(Student.name==stu_name).all() + return res +# 逻辑删除学生 +def delete_sid(db:Session,stu_id): + rs=db.query(Student).filter(Student.id==stu_id).first() + if not rs: + raise HTTPException(status_code=404, detail="学生不存在") + rs.statu=0 + db.commit() + return {"message":f"已删除编号为:{rs.stu_id}的学生:{rs.name}"}#逻辑删除 + +def create_stu(db:Session,stu): + cid=db.query(ClassInfo.id).filter(ClassInfo.class_name==stu.class_name).first() + if cid: + cid=cid.id + else: + raise HTTPException(status_code=404, detail="班级不存在") + vid=None + if stu.advisor_name: + vid=db.query(Advisor.id).filter(Advisor.name==stu.advisor_name).first() + if vid: + vid=vid.id + else: + raise HTTPException(status_code=404, detail="顾问不存在") + s_new=Student( + name=stu.name, + hometown=stu.hometown, + school = stu.school, + major = stu.major, + enroll_time = stu.enroll_time, + graduate_time = stu.graduate_time, + education = stu.education, + age = stu.age, + gender = stu.gender, + statu = 1, + advisor_id = vid, + class_id = cid + ) + db.add(s_new) + db.commit() + return {"message":"学生增加成功"} + +def update_stu(stu_id,stu,db:Session): + cid = db.query(ClassInfo.id).filter(ClassInfo.class_name == stu.class_name).first() + if cid is None: + raise HTTPException(status_code=400, detail="找不到该班级名称") + else: + cid=cid.id + if stu.advisor_name: + vid = db.query(Advisor.id).filter(Advisor.name == stu.advisor_name).first() + if vid: + vid=vid.id + else: + raise HTTPException(status_code=404, detail="顾问不存在") + s=db.query(Student).filter(Student.id==stu_id).first() + if not s: + raise HTTPException(status_code=404, detail="该学生不存在") + s.name=stu.name + s.hometown = stu.hometown + s.school = stu.school + s.major = stu.major + s.enroll_time = stu.enroll_time + s.graduate_time = stu.graduate_time + s.education = stu.education + s.age = stu.age + s.gender = stu.gender + s.advisor_id = vid + s.class_id = cid + db.commit() + return {"message":"学生信息修改成功"} + + diff --git a/dao/teacher_dao.py b/dao/teacher_dao.py new file mode 100644 index 0000000..c9804a8 --- /dev/null +++ b/dao/teacher_dao.py @@ -0,0 +1,53 @@ +# dao/users_dao.py +# 本文件封装对 Teacher表的所有数据库操作(增、删、改、查) +# dao/teacher_dao.py +# 本文件封装对 Teacher表的所有数据库操作(增、删、改、查) +# dao/teacher_dao.py +# 本文件封装对 Teacher表的所有数据库操作(增、删、改、查) +# dao/teacher_dao.py +# 本文件封装对 Teacher表的所有数据库操作(增、删、改、查) +# dao/teacher_dao.py +# 本文件封装对 Teacher表的所有数据库操作(增、删、改、查) +from sqlalchemy.orm import Session +from model.teacher import Teacher + +#新增 +def add_teacher(db:Session, teacher_no:str, name:str, phone:str): + new_teacher=Teacher( + teacher_no=teacher_no, + name=name, + phone=phone + ) + db.add(new_teacher) + db.commit() + db.refresh(new_teacher) + return new_teacher + +#查 根据id +def get_teacher_by_id(db:Session,id:int): + return db.query(Teacher).filter(Teacher.id == id, Teacher.is_deleted == 0).first() + +#逻辑删除 +def delete_teacher_logic(db:Session,id:int): + teacher=get_teacher_by_id(db,id) + if not teacher: + return None + teacher.is_deleted=1 + db.commit() + return teacher + +#修改 +def update_teacher_logic(db:Session, id:int, new_name:str=None, new_phone:str=None): + teacher = get_teacher_by_id(db, id) + if not teacher: + return None + if new_name is not None: + teacher.name = new_name + if new_phone is not None: + teacher.phone = new_phone + db.commit() + db.refresh(teacher) + return teacher + + + diff --git a/database.py b/database.py new file mode 100644 index 0000000..57030a7 --- /dev/null +++ b/database.py @@ -0,0 +1,18 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + + + +# 数据库引擎 +engine = create_engine("mysql+pymysql://root:123456@localhost/fastapi0914") +# 会话工厂 +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +Base=declarative_base() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..26db624 --- /dev/null +++ b/main.py @@ -0,0 +1,18 @@ +import uvicorn +from fastapi import FastAPI +from api import student_api,employment_api,advisor_api,teacher_api,score_api,classinfo_api,api_analysis +from database import engine +from model import Base +Base.metadata.create_all(engine) +app = FastAPI(title="沃林学生管理系统", version="1.0.0") +app.include_router(student_api.router, prefix="/students", tags=["学生模块"]) +app.include_router(employment_api.router,prefix="/employment",tags=["就业模块"]) +app.include_router(advisor_api.router,prefix="/advisor",tags=["顾问模块"]) +app.include_router(teacher_api.router,prefix="/teacher",tags=["教师模块"]) +app.include_router(score_api.router,prefix="/score",tags=["成绩模块"]) +app.include_router(classinfo_api.router,prefix="/classinfo",tags=["班级模块"]) +app.include_router(api_analysis.router,prefix="/analysis",tags=["统计分析模块"]) + +if __name__=="__main__": + Base.metadata.create_all(bind=engine) + uvicorn.run("main:app",host="localhost",port=8051,reload=True) diff --git a/model/__init__.py b/model/__init__.py new file mode 100644 index 0000000..95ebc0c --- /dev/null +++ b/model/__init__.py @@ -0,0 +1,3 @@ +from sqlalchemy.orm import declarative_base + +Base = declarative_base() \ No newline at end of file diff --git a/model/advisor.py b/model/advisor.py new file mode 100644 index 0000000..75eea4c --- /dev/null +++ b/model/advisor.py @@ -0,0 +1,17 @@ +from sqlalchemy import Column, Integer, String +from sqlalchemy.orm import declarative_base, relationship +from database import Base + +class Advisor(Base): + __tablename__ = 'advisor' + id = Column(Integer, primary_key=True, autoincrement=True) + advisor_no = Column(String(32), unique=True, nullable=False) + name = Column(String(50), nullable=False) + gender = Column(String(2), nullable=False) + phone = Column(String(20), nullable=False) + remark=Column(String(500), nullable=True) + statu = Column(Integer, default=1, nullable=False) + students=relationship("Student", back_populates="advisor") + + + diff --git a/model/classinfo.py b/model/classinfo.py new file mode 100644 index 0000000..3823db5 --- /dev/null +++ b/model/classinfo.py @@ -0,0 +1,17 @@ +from sqlalchemy import Column, Integer, String, Date +from sqlalchemy.orm import relationship +from database import Base +from model.teacher_class import teacher_class +from model.teacher import Teacher +from model.student import Student +# 导入中间关联表 + +# 班级信息表 +class ClassInfo(Base): + __tablename__="classinfo" + id=Column(Integer,primary_key=True,autoincrement=True) + class_name=Column(String(50),nullable=False,unique=True) + start_time=Column(Date) + statu=Column(Integer,default=1) # 逻辑删除表字段 1代表存在 + teachers=relationship(Teacher,secondary=teacher_class,back_populates="classinfo") + students= relationship(Student,back_populates="classinfo") \ No newline at end of file diff --git a/model/employment.py b/model/employment.py new file mode 100644 index 0000000..d783567 --- /dev/null +++ b/model/employment.py @@ -0,0 +1,20 @@ +from sqlalchemy import Column, Integer, String, Float, ForeignKey, DateTime, Date +from sqlalchemy.orm import relationship +from database import Base + +class Employment(Base): + __tablename__="employment" + id=Column(Integer,primary_key=True, autoincrement=True) + name=Column(String(50)) + stu_id=Column(Integer,ForeignKey("student.id"),unique=True,nullable=False,index=True) + employment_open_time=Column(DateTime,nullable=True) + offer_time=Column(DateTime,nullable=True) + company_name=Column(String(50),nullable=True) + salary=Column(Float,nullable=True) + is_deleted = Column(Integer, default=0, nullable=False, comment="0未删除 1已删除") + student=relationship("Student",back_populates="employment") + + + + + diff --git a/model/score.py b/model/score.py new file mode 100644 index 0000000..424a8b0 --- /dev/null +++ b/model/score.py @@ -0,0 +1,17 @@ +# model/score.py +from sqlalchemy import Column, Integer, Float, ForeignKey, DateTime +from sqlalchemy.orm import relationship +from datetime import datetime +from database import Base + + +class Score(Base): + __tablename__ = "score" + id = Column(Integer, primary_key=True, autoincrement=True) # 主键 + student_id = Column(Integer, ForeignKey("student.id"), nullable=False) #外键 + exam_seq = Column(Integer, nullable=False) + score = Column(Float, nullable=False) + is_warning = Column(Integer, default=0) #低分预警 0正常 1不及格 + is_deleted = Column(Integer, default=0) #是否被逻辑删除 + create_time = Column(DateTime, default=datetime.now) + student = relationship("Student", back_populates="scores") \ No newline at end of file diff --git a/model/student.py b/model/student.py new file mode 100644 index 0000000..e9204da --- /dev/null +++ b/model/student.py @@ -0,0 +1,29 @@ +from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, Table, Date +from sqlalchemy.orm import relationship +from model import Base + +class Student(Base): + __tablename__="student" + id = Column(Integer, primary_key=True, autoincrement=True) + stu_id=Column(String(50),unique=True) + name = Column(String(50), nullable=False) + hometown=Column(String(100)) + school = Column(String(100)) + major= Column(String(100)) + enroll_time=Column(String(100)) + graduate_time=Column(String(100)) + education=Column(String(100)) + age=Column(Integer) + gender=Column(String(10)) + statu=Column(Integer,nullable=False) + advisor_id = Column(Integer, ForeignKey("advisor.id"), nullable=True) + class_id = Column(Integer, ForeignKey("classinfo.id")) + advisor = relationship("Advisor", back_populates="students")#关联顾问 + scores = relationship("Score", back_populates="student")#关联成绩 + employment=relationship("Employment", back_populates="student")#关联就业 + classinfo = relationship("ClassInfo", back_populates="students")#关联班级 + + + + + diff --git a/model/teacher.py b/model/teacher.py new file mode 100644 index 0000000..d5769d3 --- /dev/null +++ b/model/teacher.py @@ -0,0 +1,17 @@ +from sqlalchemy import Column, Integer, String, ForeignKey,Date,DateTime +from sqlalchemy.orm import relationship +from sqlalchemy.sql import func +from model import Base +from model.teacher_class import teacher_class + + +class Teacher(Base): + __tablename__="teacher" + id=Column(Integer,primary_key=True,autoincrement=True) + teacher_no=Column(String(50),unique=True,nullable=False) + name=Column(String(50),nullable=False) + phone=Column(String(50),nullable=False) + is_deleted=Column(Integer,default=0) + created_at=Column(DateTime,server_default=func.now()) + updated_at=Column(DateTime,onupdate=func.now()) + classinfo = relationship("ClassInfo",secondary=teacher_class, back_populates="teachers") \ No newline at end of file diff --git a/model/teacher_class.py b/model/teacher_class.py new file mode 100644 index 0000000..e8dec89 --- /dev/null +++ b/model/teacher_class.py @@ -0,0 +1,12 @@ +from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, Table, Date +from sqlalchemy.orm import relationship +from model import Base + +teacher_class = Table( + "teacher_class", # 中间表的名字 + Base.metadata, # 绑定到 Base 的元数据 + Column("class_id", Integer, ForeignKey("classinfo.id"), primary_key=True), + Column("teacher_id", Integer, ForeignKey("teacher.id"), primary_key=True) , + Column("role",String(50)) + +) \ No newline at end of file diff --git a/scheme/__init__.py b/scheme/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scheme/advisor_scheme.py b/scheme/advisor_scheme.py new file mode 100644 index 0000000..2532d48 --- /dev/null +++ b/scheme/advisor_scheme.py @@ -0,0 +1,40 @@ +from typing import Optional +from pydantic import BaseModel, ConfigDict, Field + +# 新增顾问信息 +class AdvisorCreate(BaseModel): + advisor_no: str = Field(description="顾问编号") + name: str = Field(description="顾问姓名") + gender: Optional[str] = Field(description="顾问性别") + phone: Optional[str] = Field(None, description="联系电话") + remark: Optional[str] = Field(None, description="备注") + + +# 修改顾问信息 +class AdvisorUpdate(BaseModel): + name: Optional[str] = Field(None, description="顾问姓名") + gender: Optional[str] = Field(None, description="顾问性别") + phone: Optional[str] = Field(None, description="联系电话") + remark: Optional[str] = Field(None, description="备注") + +# 顾问信息响应体 +class AdvisorResp(BaseModel): + id: int + advisor_no: str + name: str + gender: str + phone: Optional[str] = None + remark: Optional[str] = None + + # Pydantic v2 写法:允许直接从 ORM 对象取值 + model_config = ConfigDict(from_attributes=True) + + +# 某个顾问名下的学生信息 +class AdvisorStudentResp(BaseModel): + id: int = Field(description="学生ID") + name: str = Field(description="学生姓名") + class_id: Optional[int] = Field(None, description="班级ID") + advisor_no: Optional[str] = Field(None, description="顾问编号") + + model_config = ConfigDict(from_attributes=True) diff --git a/scheme/classinfo_scheme.py b/scheme/classinfo_scheme.py new file mode 100644 index 0000000..5387f38 --- /dev/null +++ b/scheme/classinfo_scheme.py @@ -0,0 +1,25 @@ +# 请求和响应模型 +from datetime import date +from pydantic import BaseModel,Field +from typing import Optional + +# 新增班级 +class ClassCreate(BaseModel): + class_name: str=Field(...,min_length=2,max_length=20,description="班级名称") + start_time: Optional[date]=Field(None,description="开课时间") + +# 修改班级 +class ClassUpdate(BaseModel): + class_name: Optional[str]=Field(...,min_length=2,max_length=20,description="班级名称") + start_time: Optional[date]=Field(None,description="开课时间") + statu: Optional[int]=Field(None,ge=0,le=1,description="判断存不存在") + +# 响应模型 +class ClassIn(BaseModel): + id: int + class_name: str + start_time: Optional[date] + statu: int + + class Config: + from_attributes=True \ No newline at end of file diff --git a/scheme/employment_scheme.py b/scheme/employment_scheme.py new file mode 100644 index 0000000..0e06441 --- /dev/null +++ b/scheme/employment_scheme.py @@ -0,0 +1,38 @@ +from datetime import datetime +from pydantic import BaseModel, Field, field_validator + + + +class EmploymentCreate(BaseModel): + stu_id: int = Field(..., description="学生编号ID") + name: str | None = None + employment_open_time: datetime | None = None + offer_time: datetime | None = None + company_name: str | None = None + salary: float | None = None + + + + +class EmploymentSet(BaseModel): + name: str | None = None + stu_id: int | None = None + min_salary: float | None = None + max_salary: float | None = None + + +class EmploymentUpdate(BaseModel): + name: str | None = None + employment_open_time: datetime | None = None + offer_time: datetime | None = None + company_name: str | None = None + salary: float | None = None + +class EmploymentOut(BaseModel): + id:int + stu_id:int + name: str | None = None + employment_open_time:datetime | None = None + offer_time: datetime | None = None + company_name:str | None = None + salary:float | None = None \ No newline at end of file diff --git a/scheme/schema_analysis.py b/scheme/schema_analysis.py new file mode 100644 index 0000000..5eddfab --- /dev/null +++ b/scheme/schema_analysis.py @@ -0,0 +1,62 @@ +from datetime import datetime + +from pydantic import BaseModel, ConfigDict + + +class StudentOut(BaseModel): + model_config = ConfigDict(from_attributes=True) + id: int + name: str + age: int | None = None + class_id: int | None = None + + +class StudentGenderOut(BaseModel): + model_config = ConfigDict(from_attributes=True) + class_id: int | None = None + total: int + gender_male: int + gender_female: int + + +class StudentRecordOut1(BaseModel): + model_config = ConfigDict(from_attributes=True) + id: int + name: str + score: float + + +class StudentRecordOut2(BaseModel): + model_config = ConfigDict(from_attributes=True) + id: int + name: str + class_id: int | None = None + score: float + + +class StudentRecordOut3(BaseModel): + model_config = ConfigDict(from_attributes=True) + exam_seq: int + class_name: str + avg_score: float + + +class StudentRecordOut4(BaseModel): + model_config = ConfigDict(from_attributes=True) + name: str + class_id: int | None = None + employment_open_time: datetime | None = None + company_name: str | None = None + salary: float | None = None + + +class StudentRecordOut5(BaseModel): + model_config = ConfigDict(from_attributes=True) + stu_id: int + time_diff: float + + +class StudentRecordOut6(BaseModel): + model_config = ConfigDict(from_attributes=True) + class_id: int | None = None + time_diff: float diff --git a/scheme/score_scheme.py b/scheme/score_scheme.py new file mode 100644 index 0000000..90215f8 --- /dev/null +++ b/scheme/score_scheme.py @@ -0,0 +1,28 @@ +# scheme/score_scheme.py +from pydantic import BaseModel, Field + + +# 录入成绩 +class ScoreCreate(BaseModel): + student_id: int = Field(..., description="ID") + exam_seq: int = Field(..., ge=1, description="第几次") + score: float = Field(..., ge=0, le=100, description="分数") + +# 修改成绩 +class ScoreUpdate(BaseModel): + student_id: int = Field(..., description="ID") + exam_seq: int = Field(..., ge=1, description="第几次") + score: float = Field(..., ge=0, le=100, description="分数") + + +# 返回前端 +class ScoreOut(BaseModel): + id: int + student_id: int + exam_seq: int + score: float + is_warning: int + create_time: str | None = None + + class Config: + from_attributes = True \ No newline at end of file diff --git a/scheme/student_scheme.py b/scheme/student_scheme.py new file mode 100644 index 0000000..c694ea8 --- /dev/null +++ b/scheme/student_scheme.py @@ -0,0 +1,22 @@ +from pydantic import BaseModel,Field,field_validator +from typing import Optional +from model import student + +class Create_Stu_Mod(BaseModel): + name: str = Field(min_length=3, max_length=15,description="姓名") + hometown :Optional[str]=Field(min_length=2) + school :str= Field(min_length=2,description="毕业院校") + major : str=Field(description="专业") + enroll_time:Optional[str]=Field(None,description="入学时间") + graduate_time:Optional[str] = Field(None,description="毕业时间") + education :Optional[str] = Field(description="学历") + age :int=Field(gt=14,lt=60,description="年龄") + gender : str = Field(max_length=10,description="性别") + advisor_name:Optional[str]=Field(description="顾问名字") + class_name:str=Field(description="班级名称") + # 自定义校验器 + @field_validator('gender') + def gender_validator(cls, gender): + if gender not in ['男','女']: + raise ValueError('性别输入有误') + return gender diff --git a/scheme/teacher_scheme.py b/scheme/teacher_scheme.py new file mode 100644 index 0000000..1a401f7 --- /dev/null +++ b/scheme/teacher_scheme.py @@ -0,0 +1,14 @@ +from pydantic import BaseModel, Field +from typing import Optional + +class TeacherBase(BaseModel): + teacher_no: str = Field(..., max_length=50, description="教师编号") + name: str = Field(..., max_length=50, description="教师姓名") + phone: str = Field(..., max_length=50, description="手机号") + +class TeacherCreate(TeacherBase): + pass + +class TeacherUpdate(BaseModel): + name: Optional[str] = Field(None, max_length=50, description="教师姓名") + phone: Optional[str] = Field(None, max_length=50, description="手机号") diff --git a/test.py b/test.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/test.py @@ -0,0 +1 @@ +