diff --git a/api/student.py b/api/student.py index 99daec7..996c47a 100644 --- a/api/student.py +++ b/api/student.py @@ -1,14 +1,96 @@ -from fastapi import APIRouter,Depends,HTTPException +from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session -from dao.student import * -from schemas.student import StudentCreate +from core.database import get_db +from schemas.student import StudentCreate, StudentUpdate +from dao import student as student_dao student_router = APIRouter() -@student_router.post("/student") -def create_student(request:StudentCreate,db:Session=Depends(create_students)): +@student_router.post("",summary='添加学生') +def create_student(request:StudentCreate,db:Session = Depends(get_db)): d = request.model_dump() - r = create_students(d,db) + r = student_dao.create_students(d,db) if not r: raise HTTPException(status_code=500,detail='服务器繁忙,请稍后添加!') - return {'code':200,'detail':"添加学生成功"} \ No newline at end of file + return {'code':200,'detail':"添加学生成功"} + +@student_router.put("/{id}", summary="修改学生") +def update_student( + id: int, + request: StudentUpdate, + db: Session = Depends(get_db), +): + # 只取前端真正传来的字段 + # 例如只传 age,就只修改 age + data = request.model_dump(exclude_unset=True) + + student = student_dao.update_student(id, data, db) + + # None 表示学生不存在 + if student is None: + raise HTTPException(status_code=404, detail="学生不存在") + + # False 表示操作数据库失败 + if student is False: + raise HTTPException(status_code=500, detail="修改学生失败") + + return { + "code": 200, + "detail": "修改学生成功", + "data": student, + } + +@student_router.get("", summary="查询学生列表") +def get_students( + # 三个查询条件都可以不传 + student_no: str | None = None, + student_name: str | None = None, + class_id: int | None = None, + # 获取本次请求使用的数据库连接 + db: Session = Depends(get_db), +): + # 调用 DAO 查询数据库 + students = student_dao.get_students( + db=db, + student_no=student_no, + student_name=student_name, + class_id=class_id, + ) + + return { + "code": 200, + "detail": "查询成功", + "total": len(students), + "data": students, + } + +@student_router.get("/{id}", summary="查询学生详情") +def get_student(id: int, db: Session = Depends(get_db)): + # 根据路径中的 ID 查询学生 + student = student_dao.get_student_by_id(id, db) + + if not student: + # 404 表示请求的数据不存在 + raise HTTPException(status_code=404, detail="学生不存在") + + return { + "code": 200, + "detail": "查询成功", + "data": student, + } + +@student_router.delete("/{id}", summary="逻辑删除学生") +def delete_student(id: int, db: Session = Depends(get_db)): + student = student_dao.delete_student(id, db) + + # None 表示不存在,或者以前已经删除 + if student is None: + raise HTTPException(status_code=404, detail="学生不存在或已经删除") + + if student is False: + raise HTTPException(status_code=500, detail="删除学生失败") + + return { + "code": 200, + "detail": "删除学生成功", + } diff --git a/dao/student.py b/dao/student.py index 9014fe5..e11ce68 100644 --- a/dao/student.py +++ b/dao/student.py @@ -1,16 +1,103 @@ from schemas.student import * from core.database import get_db from models.student import * -from utils.code_generator import generate_no +from sqlalchemy.orm import Session -def create_students(d,db): +def create_students(d: dict, db: Session): stu = Student(**d) + try: db.add(stu) - generate_no("student_no", "STU", stu, db) + # 把 SQL 发给数据库执行 + db.flush() + # 根据 id 生成学生编号 + if not stu.student_no: + stu.student_no = f"STU{stu.id:04d}" db.commit() - except:return False - else: - return True + db.refresh(stu) + return stu + except Exception as e: + db.rollback() + print(f"插入学生失败: {e}") + return None + +def get_student_by_id(student_id: int, db: Session): + # 同时判断 is_deleted,已经逻辑删除的学生不会被查到 + return db.query(Student).filter( + Student.id == student_id, + Student.is_deleted == 0, + ).first() + +def update_student(student_id: int, data: dict, db: Session): + # 第一步:先查询学生 + student = get_student_by_id(student_id, db) + + # 没有查到就返回 None + if not student: + return None + + try: + # 第二步:循环修改前端传来的字段 + # field 是字段名,value 是新的值 + for field, value in data.items(): + setattr(student, field, value) + + # 第三步:提交修改并重新读取数据 + db.commit() + db.refresh(student) + return student + + except Exception as e: + # 修改失败时回滚 + db.rollback() + print("修改学生失败:", e) + return False + +def get_students( + db: Session, + student_no: str | None = None, + student_name: str | None = None, + class_id: int | None = None, +): + # 第一步:只查询没有被删除的学生 + query = db.query(Student).filter(Student.is_deleted == 0) + + # 第二步:前端传了哪个条件,就增加哪个条件 + if student_no: + # 学号使用精确查询 + query = query.filter(Student.student_no == student_no) + + if student_name: + # 姓名使用模糊查询,例如“张”可以查到“张三” + query = query.filter(Student.student_name.like(f"%{student_name}%")) + + if class_id: + # 班级 ID 使用精确查询 + query = query.filter(Student.class_id == class_id) + + # 第三步:执行查询并返回全部结果 + return query.all() + +#逻辑删除学生 +def delete_student(student_id: int, db: Session): + # 第一步:查询学生 + student = get_student_by_id(student_id, db) + + if not student: + return None + + try: + # 第二步:不真正删除记录,只把删除标记改成 1 + student.is_deleted = 1 + + # 第三步:提交修改 + db.commit() + return student + + except Exception as e: + # 删除失败时回滚 + db.rollback() + print("删除学生失败:", e) + return False diff --git a/database.py b/database.py index ecff48f..7ee23b9 100644 --- a/database.py +++ b/database.py @@ -10,4 +10,4 @@ engine = create_engine(db_url Base.metadata.create_all(engine) db = SessionLocal() -db.commit() \ No newline at end of file +db.commit() #创建全部表 \ No newline at end of file diff --git a/main.py b/main.py index e136053..a145808 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ from fastapi import FastAPI from api.example import example_router from middleware import log_middleware -from api.statistics import statistics_router +# from api.statistics import statistics_router import uvicorn from api.student import student_router app = FastAPI() @@ -12,15 +12,15 @@ from api.class_api import classes_router app.include_router(classes_router,tags=['班级接口'],prefix="/classes") #-------------李玉杰-------------- -app.include_router(student_router) +app.include_router(student_router,tags=['学生接口'],prefix="/students") #-------------张义--------------- #-------------薄鑫--------------- from api import consultant app.include_router(consultant.router) #-------------张昕浩--------------- -app.include_router(example_router) -app.include_router(statistics_router, prefix="/statistics") +# app.include_router(example_router) +# app.include_router(statistics_router, prefix="/statistics") #-------------曾凯--------------- diff --git a/models/student.py b/models/student.py index ab805e4..fc73e95 100644 --- a/models/student.py +++ b/models/student.py @@ -10,7 +10,8 @@ class Student(Base): , comment = '学生编号,自增主键' ) student_no = Column(VARCHAR(50) - , unique = True) + ,nullable = True + ,unique = True) student_name = Column(VARCHAR(50)) class_id = Column(Integer ,ForeignKey('class_info_detail.id') diff --git a/schemas/student.py b/schemas/student.py index d4a044a..47f9b13 100644 --- a/schemas/student.py +++ b/schemas/student.py @@ -1,18 +1,40 @@ from pydantic import BaseModel from datetime import date +from pydantic import BaseModel, ConfigDict, Field, model_validator class StudentCreate(BaseModel): - student_no: str|None = None - student_name: str - class_id: int - consultant_id: int | None = None - native_place: str | None = None - graduate_school: str | None = None - major: str | None = None + student_no: str | None = Field(default=None, min_length=1, max_length=50) + student_name: str = Field(min_length=1, max_length=50) + class_id: int = Field(gt=0) + consultant_id: int | None = Field(default=None, gt=0) + native_place: str | None = Field(default=None, max_length=100) + graduation_school: str | None = Field(default=None, max_length=100) + major: str | None = Field(default=None, max_length=100) enrollment_date: date graduation_date: date | None = None + education: str | None = Field(default=None, max_length=50) + age: int = Field(ge=0, le=150) + gender: str = Field(min_length=1, max_length=10) + + @model_validator(mode="after") + def check_dates(self): + # 3. 新增时两个日期都已确定,可以直接校验先后顺序。 + if self.graduation_date and self.graduation_date < self.enrollment_date: + raise ValueError("毕业日期不能早于入学日期") + return self + +class StudentUpdate(BaseModel): + # 全部设为可选,前端只传需要修改的字段 + student_no: str | None = None + student_name: str | None = None + class_id: int | None = None + consultant_id: int | None = None + native_place: str | None = None + graduation_school: str | None = None + major: str | None = None + enrollment_date: date | None = None + graduation_date: date | None = None education: str | None = None - age: int - gender: str - + age: int | None = None + gender: str | None = None diff --git a/utils/code_generator.py b/utils/code_generator.py index 07b61d0..3320511 100644 --- a/utils/code_generator.py +++ b/utils/code_generator.py @@ -33,8 +33,8 @@ def add_student( ''' - -def generate_no(field_name: str, prefix: str, db_object, db): +from sqlalchemy.orm import Session +def generate_no(field_name: str, prefix: str, db_object, db: Session): if getattr(db_object, field_name): return