初始化前后端学生管理系统项目

This commit is contained in:
2026-09-21 19:15:28 +08:00
commit 8a35871cea
63 changed files with 5723 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
from sqlalchemy_fastapi_demo_1.model.Score import Score
from sqlalchemy_fastapi_demo_1.model.students import Student
from sqlalchemy.orm import Session
from sqlalchemy_fastapi_demo_1.scheme.Score import ScoreCreate,ScoreUpdate
class ScoreDAO:
"""用户数据访问对象,所有方法均为静态方法,方便调用"""
@staticmethod
def inspect_stu_id_unq(db:Session,stu_id:int):
return db.query(Student).filter(Student.stu_id == stu_id,Student.is_deleted==0).first()
# 查所有数据
@staticmethod
def get_all(db:Session,skip:int=0,limit:int=100):
return db.query(Score).offset(skip).limit(limit).all()
# 查询单个数据
@staticmethod
def get_by_id(db:Session,stu_id:int,exam_id:int):
return db.query(Score).filter(Score.stu_id == stu_id,Score.exam_id==exam_id).first()
# 添加数据
@staticmethod
def post_score(db:Session,score_create:ScoreCreate):
# 将 Pydantic 模型转为字典,并解包构建 SQLAlchemy 模型实例
db_score=Score(**score_create.model_dump())
db.add(db_score) #添加到会话
db.commit() #提交事务,此时会执行 INSERT,并自动填充自增字段
db.refresh(db_score) #刷新对象,获取数据库生成的默认值(如 created_at)
return db_score
# 更改数据
@staticmethod
def put_score(db:Session,score_id:int,exam_id:int,score_update:ScoreUpdate):
db_score=ScoreDAO.get_by_id(db,score_id,exam_id)
if not db_score:
return None
# 只更新客户端显式传入的字段(exclude_unset=True 排除未设置的字段)
put_score_data = score_update.model_dump(exclude_unset=True)
for k,v in put_score_data.items():
setattr(db_score,k,v) # 动态设置属性
db.commit()
db.refresh(db_score)
return db_score
# 删除
@staticmethod
def delete_score(db:Session,score_id:int,exam_id:int):
db_score=ScoreDAO.get_by_id(db,score_id,exam_id)
if not db_score:
return False
db.delete(db_score)
db.commit()
return True
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
View File
+56
View File
@@ -0,0 +1,56 @@
from sqlalchemy.orm import Session
from sqlalchemy_fastapi_demo_1.model.advisors import Advisor
from sqlalchemy_fastapi_demo_1.model.students import Student
def create_advisor(db:Session,advisor_id:int,advisor_name:str):
advisor = Advisor(advisor_id=advisor_id,advisor_name=advisor_name)
db.add(advisor)
db.commit()
db.refresh(advisor)
return advisor
def search_advisor(db:Session,advisor_id:int|None=None,advisor_name:str|None=None):
if advisor_id is None and advisor_name is None:
return None
query=db.query(Advisor)
if advisor_id is not None:
query = query.filter(Advisor.advisor_id == advisor_id)
if advisor_name is not None:
query = query.filter(Advisor.advisor_name==advisor_name)
advisor = query.first()
return advisor
def list_advisors(db: Session,advisor_name: str|None =None):
query = db.query(Advisor)
if advisor_name is not None:
query = query.filter(Advisor.advisor_name.like(f"%{advisor_name}%"))
return query.all()
def list_students_of_advisor(db: Session, advisor_id: int):
"""查这个顾问名下还没被逻辑删除的学生"""
return db.query(Student).filter(
Student.is_deleted == 0,
Student.advisor_id == advisor_id,
).all()
def update_advisor(db:Session,advisor_id:int,advisor_name:str|None=None):
r_advisor = search_advisor(db=db,advisor_id=advisor_id)
if r_advisor is None:
return None
if advisor_name is not None:
r_advisor.advisor_name = advisor_name
db.commit()
return r_advisor
def delete_advisor(db:Session,advisor_id:int):
d_advisor = search_advisor(db=db,advisor_id=advisor_id)
if d_advisor is None:
return None
db.delete(d_advisor)
db.commit()
return advisor_id
+41
View File
@@ -0,0 +1,41 @@
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from sqlalchemy_fastapi_demo_1.dao.advisor import crud
from sqlalchemy_fastapi_demo_1.scheme.advisors import AdvisorIn
# 成功 (数据, None);失败 (None, "错误码")。
def create_advisor(db:Session,advisor_id:int,advisor_name:str):
exist=crud.search_advisor(db,advisor_id=advisor_id)
if exist is not None:
return None,"DUPLICATE" #ID主键已被占用
try:
advisor = crud.create_advisor(db,advisor_id,advisor_name)
except IntegrityError:
db.rollback()
return None, "DUPLICATE"
return advisor, None
def update_advisor(db:Session,advisor_id:int,advisor_in:AdvisorIn):
exist = crud.search_advisor(db,advisor_id=advisor_id)
if exist is None:
return None, "NOT_FOUND"
u_advisor=crud.update_advisor(db,advisor_id=advisor_id,advisor_name=advisor_in.advisor_name)
if u_advisor is None:
return None, "NOT_FOUND" # 查过之后被并发删掉了
return u_advisor,None
#删除成功返回Advisor ID,删除失败返回None。顾问如连接学生,则拒绝删除。
def delete_advisor(db: Session, advisor_id: int):
exist = crud.search_advisor(db=db, advisor_id=advisor_id)
if exist is None:
return None, "NOT_FOUND"
# 查一下这个顾问名下有没有学生
if crud.list_students_of_advisor(db, advisor_id):
return None, "HAS_STUDENTS"
result = crud.delete_advisor(db=db, advisor_id=advisor_id)
if result is None:
return None, "NOT_FOUND" # 查过之后被并发删掉了
return result, None
+68
View File
@@ -0,0 +1,68 @@
# # dao/c_lass.py 数据访问层,直接操作数据库
# # 本文件封装对 Classinfo表的所有数据库操作(增、删、改、查)
from sqlalchemy.orm import Session # 会话类型,标注db参数
from sqlalchemy_fastapi_demo_1.model.c_lass import Classinfo # # 导入ORM模型
from sqlalchemy_fastapi_demo_1.scheme.c_lass import ClassCreate, ClassUpdate # 导入入参模型
from typing import Optional, List # 类型注解用:Optional=可空,List=列表
# 新增班级
def create_c_lass(db: Session, obj: ClassCreate):# 新增函数:接收会话db和校验后的数据obj,返回Classinfo对象
db_obj = Classinfo(class_id=obj.class_id, start_time=obj.start_time)
# 把前端传来的数据组装成一个ORM对象(相当于内存里的一条新记录)
db.add(db_obj) # 把对象加入会话
db.commit() # 提交事务:真正把INSERT语句发给MySQL执行,写进数据库
db.refresh(db_obj) # 从数据库重新查一遍这条记录,把数据库自动生成的值(如默认值)刷新回对象
return db_obj # 返回这个对象,方便API层序列化成JSON返回前端
# 根据 id 查询单个班级:只查询 is_deleted=0 未删除
def get_c_lass(db: Session, class_id: int) -> Optional[Classinfo]:
# 按ID查单个班级;Optional = 可能查不到(返回None)
return db.query(Classinfo).filter(
Classinfo.class_id == class_id,# 条件1:班级编号等于传入的id
Classinfo.is_deleted == 0 # 条件2:没被逻辑删除(只查0)
).first()
# .first() = 取第一条;查不到就返回None,不会报错
# 分页查询所有班级:过滤已经逻辑删除的数据
def get_all_c_lass(db: Session, skip: int = 0, limit: int = 100) -> List[Classinfo]:
# 分页查所有班级:skip=跳过几条,limit=最多取几条
return db.query(Classinfo)\
.filter(Classinfo.is_deleted == 0)\
.offset(skip).limit(limit).all() # # 只查没删的; 跳过skip条,取limit条,返回列表
# 修改班级(局部更新:传了哪个字段就改哪个)
def update_c_lass(db: Session, class_id: int, update_obj: ClassUpdate):
# 修改函数:按id找到班级,把传进来的字段改掉
db_class = get_c_lass(db, class_id)
# 只取前端真正传了的字段
update_data = update_obj.model_dump(exclude_unset=True)
# 把前端传的修改数据转成字典;exclude_unset=True = 只保留前端真正传了的字段
# (没传的字段不出现,就不会被误改成None——就是"局部更新")
for key, value in update_data.items():# 循环:把字典里每个字段的值,赋给ORM对象对应属性(内存里改好)
setattr(db_class, key, value)
db.commit() # 提交:把改动写进数据库
db.refresh(db_class) # 从数据库重新查询这条记录,把数据库里的最新值刷新到 Python 对象上,让内存里的对象和数据库保持一致。
return db_class # 返回改好的对象
# 逻辑删除:不再db.delete,设置is_deleted=1
def delete_c_lass(db: Session, class_id: int) -> bool:
# 删除函数:不是物理删除(不删数据库行),是打标记
db_class = get_c_lass(db, class_id) # 先查这条班级
if not db_class:
return False # 查不到返回False,API层返回404
# 打删除标记
db_class.is_deleted = 1 # 把逻辑删除标记改成1(=已删除
db.commit()
return True # 返回True表示删除成功
#DAO 层是所有 SQL 的家,API 层不写任何 SQL,只调这里的函数。
# 查询统一过滤 `is_deleted == 0`,删了的数据还在数据库里,只是查不到 —— 这就是逻辑删除。
+175
View File
@@ -0,0 +1,175 @@
from fastapi import HTTPException
from sqlalchemy.orm import Session
from sqlalchemy import and_, Date
from sqlalchemy_fastapi_demo_1.model.employment import EmploymentBase,EmploymentOffer
from sqlalchemy_fastapi_demo_1.model.students import Student
# ========== 就业基础信息 DAO ==========
class EmploymentBaseDAO:
@staticmethod
#根据学生编号查询
def get_by_stu_id(db: Session, stu_id: int):
record = db.query(EmploymentBase).filter(and_(
EmploymentBase.stu_id == stu_id,
EmploymentBase.is_deleted == 0
)).first()
return record
@staticmethod
#多条件查询
def different_choice_query(
db: Session,
stu_id: int = None,
company_name: str = None,
min_salary: float = None,
max_salary: float = None,
skip: int = 0,
limit: int = 10
):
# 基础查询 + 过滤未删除
query = db.query(EmploymentBase).filter(EmploymentBase.is_deleted == 0)
# 动态拼接条件
#学生id查询
if stu_id is not None:
query = query.filter(EmploymentBase.stu_id == stu_id)
#公司名称查询
if company_name is not None and company_name.strip() != "":
# 模糊匹配,%代表通配符
query = query.filter(EmploymentBase.company_name.like(f"%{company_name}%"))
#工资范围查询
if min_salary is not None:
query = query.filter(EmploymentBase.salary >= min_salary)
if max_salary is not None:
query = query.filter(EmploymentBase.salary <= max_salary)
# 分页
result = query.offset(skip).limit(limit).all()
return result
@staticmethod
#新增学生就业基础信息
def create(db: Session, obj: EmploymentBase):
student = db.query(Student).filter(
Student.stu_id == obj.stu_id,
Student.is_deleted == 0
).first()
if not student:
raise HTTPException(status_code=400, detail="学生不存在或已逻辑删除,不能添加就业信息")
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@staticmethod
#更新就业基础信息
def update(db: Session, stu_id: int, update_data: dict):
record = EmploymentBaseDAO.get_by_stu_id(db, stu_id)
if not record:
return None
if "company_name" in update_data:
record.company_name = update_data["company_name"]
if "salary" in update_data:
record.salary = update_data["salary"]
if "employment_open_time" in update_data:
record.employment_open_time = update_data["employment_open_time"]
if "job_time" in update_data:
record.job_time = update_data["job_time"]
# =========== 统一时间校验 ===========
final_emp_open = record.employment_open_time
final_job = record.job_time
# 两个时间都不为空才校验
if final_emp_open and final_job:
if final_job < final_emp_open:
raise ValueError("job时间不能早于就业开放时间")
db.commit()
db.refresh(record)
return record
@staticmethod
#根据学生编号对就业基础表进行逻辑删除
def delete(db: Session, stu_id: int):
record = EmploymentBaseDAO.get_by_stu_id(db, stu_id)
if not record:
return False
record.is_deleted = 1
db.commit()
return True
# ========== 就业Offer协议 DAO ==========
class EmploymentOfferDAO:
@staticmethod
#添加就业协议记录
def create(db: Session, obj_1: EmploymentOffer,obj_2:EmploymentBase):
# 时间校验
if obj_1.offer_time < obj_2.employment_open_time:
raise ValueError("offer时间不能早于就业开放时间")
db.add(obj_1)
db.commit()
db.refresh(obj_1)
return obj_1
@staticmethod
#修改就业协议表
def update(db: Session, stu_id: int, offer_id: int, offer_time:Date):
"""修改offer"""
record_list = EmploymentOfferDAO.different_choice_query(db, stu_id, offer_id)
if not record_list:
return None
record = record_list[0]
#查询就业基础信息,拿到就业开放时间准备做时间校验
base_record = db.query(EmploymentBase).filter(
EmploymentBase.stu_id == stu_id,
EmploymentBase.is_deleted == 0
).first()
#避免就业基础信息被逻辑删除了而就业基础协议记录还存在
if not base_record:
raise ValueError("未找到该学生就业基础信息")
#时间校验
if offer_time is not None:
if offer_time < base_record.employment_open_time:
raise ValueError("offer时间不能早于就业开放时间")
record.offer_time = offer_time
db.commit()
db.refresh(record)
return record
@staticmethod
#根据协议编号对就业协议表进行逻辑删除
def delete(db: Session, stu_id: int,offer_id: int):
"""offer逻辑删除"""
record_list = EmploymentOfferDAO.different_choice_query(db, stu_id,offer_id)
if not record_list:
return False
record = record_list[0]
record.is_deleted = 1
db.commit()
return True
@staticmethod
#多条件查询就业协议表
def different_choice_query(
db: Session,
stu_id: int =None ,
offer_id: int = None,
skip: int = 0,
limit: int = 10
):
#基础查询+过滤未删除
query = db.query(EmploymentOffer).filter(EmploymentOffer.is_deleted == 0)
#动态拼接条件
#学生id查询(选填)
if stu_id is not None:
query = query.filter(EmploymentOffer.stu_id == stu_id)
# 同时传了offer编号 → 查单个(联合主键两个都查)
if offer_id is not None:
query = query.filter(EmploymentOffer.offer_id == offer_id)
elif stu_id is None and offer_id is not None:
raise ValueError("不能单独查询offer编号,必须同时提供学生编号")
# 分页
result = query.offset(skip).limit(limit).all()
return result
+110
View File
@@ -0,0 +1,110 @@
from sqlalchemy import func, case
from sqlalchemy_fastapi_demo_1.model.students import Student
from sqlalchemy_fastapi_demo_1.model.Score import Score
from sqlalchemy_fastapi_demo_1.model.employment import EmploymentBase,EmploymentOffer
from sqlalchemy_fastapi_demo_1.model.c_lass import Classinfo
def students_age(db,op:str,
age_value: int = None,
age_min: int = None,
age_max: int = None):
a=db.query(Student).filter(Student.is_deleted == 0)
if op == ">":
a=a.filter(Student.age > age_value)
elif op == "<":
a=a.filter(Student.age < age_value)
elif op == "=":
a=a.filter(Student.age == age_value)
elif op == ">=":
a=a.filter(Student.age >= age_value)
elif op == "<=":
a=a.filter(Student.age <= age_value)
elif op == "between":
if age_min is None or age_max is None:
raise ValueError("区间查询必须提供 age_min和age_max")
a=a.filter(Student.age.between(age_min, age_max))
else:
raise ValueError("请使用 >, <, =, >=, <=, between")
return a.all()
# 多维度班级统计**:统计每个班级的总人数,以及按性别(男、女)细分的人数分布。
def class_statistics(db):
a = (db.query(Student.class_id,func.count(Student.stu_id).label("total"),
func.sum(case((Student.gender == "男", 1), else_=0)).label("male"),
func.sum(case((Student.gender == "女", 1), else_=0)
).label("female"))
.filter(Student.is_deleted==0).group_by(Student.class_id).all())
list1 = []
for i in a:
list1.append({"class_id": i.class_id,"total": i.total,"male": i.male,"female": i.female})
return list1
# - 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩。
def score_above(db,score_input):
result = []
for stu in db.query(Student).filter(Student.is_deleted == 0).all():
if stu.score and all(s.score >= score_input for s in stu.score):
for s in stu.score:
result.append((stu.stu_id, stu.stu_name, s.exam_id, s.score))
return result
# - 查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细。
def score_fail(db, fail_times, fail_score=60):
result = []
for stu in db.query(Student).filter(Student.is_deleted == 0).all():
fails = [s for s in stu.score if s.score < fail_score]
if len(fails) >= fail_times:
for s in fails:
result.append((stu.stu_name, stu.class_id, s.score))
return result
# - 统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序。
def avg_scores(db, order="desc"):
avg = func.avg(Score.score).label("avg_score")
a = (db.query(Score.exam_id,Student.class_id,avg)
.join(Score.student).filter(Student.is_deleted == 0)
.group_by(Score.exam_id,Student.class_id))
a = a.order_by(avg.desc() if order == "desc" else avg.asc())
return a.all()
# - 统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司。
def top_salary(db, n):
a = (db.query(Student.stu_name,
Student.class_id,
EmploymentBase.job_time,
EmploymentBase.company_name,
EmploymentBase.salary).join(Student, EmploymentBase.stu_id == Student.stu_id)
.filter(EmploymentBase.is_deleted == 0, Student.is_deleted == 0)
.order_by(EmploymentBase.salary.desc()).offset(n-1).limit(1).first())
if not a:
return None
return {"name": a.stu_name,"class_id": a.class_id,"job_time": str(a.job_time) if a.job_time else None,
"company": a.company_name,"salary": a.salary}
# - 统计每个学生的就业时长(计算公式:offer下发时间 - 就业开放时间)。
def stu_every(db):
a = (db.query(Student.stu_id,
Student.stu_name,
EmploymentBase.employment_open_time,
EmploymentOffer.offer_time)
.join(EmploymentBase, EmploymentBase.stu_id == Student.stu_id)
.join(EmploymentOffer, EmploymentOffer.stu_id == Student.stu_id)
.filter(Student.is_deleted == 0,EmploymentBase.is_deleted == 0,
EmploymentOffer.is_deleted == 0).all())
return [{"stu_id": sid,"name": name,
"days": (offer_t - open_t).days if open_t and offer_t else None}
for sid, name, open_t, offer_t in a]
# - 统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生)。
def class_avg(db):
days = func.datediff(EmploymentOffer.offer_time,
EmploymentBase.employment_open_time).label("days")
a = (db.query(Student.class_id,
func.avg(days).label("avg_days"),
func.count().label("count"))
.join(EmploymentBase, EmploymentBase.stu_id == Student.stu_id)
.join(EmploymentOffer, EmploymentOffer.stu_id == Student.stu_id)
.filter(Student.is_deleted == 0,
EmploymentBase.is_deleted == 0,
EmploymentOffer.is_deleted == 0,
EmploymentBase.employment_open_time.isnot(None)).group_by(Student.class_id).all())
return [{"class_id": i.class_id, "avg_days": round(float(i.avg_days), 2)} for i in a]
+115
View File
@@ -0,0 +1,115 @@
# dao/students_dao.py
# 本文件封装对 model 表的所有数据库操作(增、删、改、查)
from sqlalchemy.orm import Session
from fastapi import HTTPException
from sqlalchemy_fastapi_demo_1.model.c_lass import Classinfo
from sqlalchemy_fastapi_demo_1.model.advisors import Advisor
from sqlalchemy_fastapi_demo_1.model.students import Student
from sqlalchemy_fastapi_demo_1.scheme.students import StudentCreate, StudentUpdate
from typing import Optional, List
class StudentDAO:
@staticmethod
def inspect_class_id_unq(db: Session, class_id: int):
"""校验班级是否存在:去 c_lass 表查"""
return db.query(Classinfo).filter(Classinfo.class_id == class_id).first()
@staticmethod
def inspect_advisor_id_unq(db: Session, advisor_id: int):
"""校验顾问是否存在:去 advisors 表查"""
return db.query(Advisor).filter(Advisor.advisor_id == advisor_id).first()
@staticmethod
def create_student(db: Session, obj_in: StudentCreate):
"""新增学生,检查学号唯一性"""
exist = db.query(Student).filter(Student.stu_id == obj_in.stu_id).first()
# 只按 stu_id 判断,且包含逻辑删除的记录
if exist:
if exist.is_deleted == 1:
raise HTTPException(status_code=400, detail="该学号已被占用(处于逻辑删除状态),请先恢复")
raise HTTPException(status_code=400, detail="该学生已存在")
db_obj = Student(**obj_in.model_dump())
try:
db.add(db_obj)
db.commit()
db.refresh(db_obj)
except Exception:
db.rollback()
raise
return db_obj
@staticmethod
def get_students_all(db: Session, skip: int = 0, limit: int = 100):
"""分页查询全部学生"""
return db.query(Student).filter(Student.is_deleted == 0).offset(skip).limit(limit).all()
@staticmethod
def get_student_by_id(db: Session, stu_id: int):
"""根据学生编号单条查询"""
return db.query(Student).filter(Student.is_deleted == 0,
Student.stu_id == stu_id).first()
@staticmethod
def query_multi_condition(
db: Session,
stu_id: Optional[int] = None,
stu_name: Optional[str] = None,
class_id: Optional[int] = None,
skip: int = 0,
limit: int = 100
) :
q = db.query(Student).filter(Student.is_deleted == 0)
"""多条件选择性查询"""
# 只有参数不为None的时候,才加上查询条件
if stu_id is not None:
q = q.filter(Student.stu_id == stu_id)
if stu_name is not None:
q = q.filter(Student.stu_name.like(f"%{stu_name}%"))
if class_id is not None:
q = q.filter(Student.class_id == class_id)
q = q.offset(skip).limit(limit)
return q.all()
@staticmethod
def update_student(db: Session,stu_id:int, obj: StudentUpdate):
db_obj = db.query(Student).filter(Student.stu_id == stu_id,
Student.is_deleted == 0).first()
if not db_obj:
raise HTTPException(status_code=404, detail="学生数据不存在或已删除")
update_data = obj.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(db_obj, field, value)
try:
db.commit()
db.refresh(db_obj)
except Exception:
db.rollback()
raise
return db_obj
@staticmethod
def delete_student(db: Session, stu_id: int):
db_obj = db.query(Student).filter(Student.stu_id == stu_id,
Student.is_deleted == 0).first()
if not db_obj:
raise HTTPException(status_code=404, detail="学生数据不存在或已删除")
db_obj.is_deleted = 1
try:
db.commit()
db.refresh(db_obj)
except Exception:
db.rollback()
raise
return True # 返回布尔值,而不是 dict
+67
View File
@@ -0,0 +1,67 @@
# dao/teachers_dao.py
# 本文件封装对 Teacher 表的所有数据库操作(增、删、改、查)
from sqlalchemy.orm import Session
from sqlalchemy_fastapi_demo_1.scheme.teachers import TeacherAdd, TeacherUpdate
from sqlalchemy_fastapi_demo_1.model.teachers import Teacher
from sqlalchemy_fastapi_demo_1.model.c_lass import Classinfo
class TeacherDAO:
@staticmethod
def add_teacher(db:Session,teacher_data:TeacherAdd): # 前端返回的teacher_data是1个Pydantic对象
db_teacher=Teacher(**(teacher_data.model_dump()))
db.add(db_teacher)
db.commit()
db.refresh(db_teacher)
return db_teacher
@staticmethod
def inspect_teacher_id_unq(db: Session, teacher_id: int):
"""
根据教师ID获取教师对象(用于主键唯一性检查,查询结果包含被软删除的对象)
"""
return db.query(Teacher).filter(Teacher.teacher_id == teacher_id).first()
@staticmethod
def inspect_class_id_unq(db: Session, class_id: int):
"""
根据班级ID获取班级对象(用于外键检查,查询结果排除被软删除对象,即不包括is_deleted=1的对象)
"""
return db.query(Classinfo).filter(Classinfo.class_id == class_id,Classinfo.is_deleted==0).first()
@staticmethod
def delete_light(db: Session, teacher_id: int):
"""
删除教师
:return: True 表示删除成功,False 表示教师ID不存在,已被软删除或硬删除
"""
db_teacher = TeacherDAO.inspect_teacher_id_unq(db, teacher_id)
if (not db_teacher) or db_teacher.is_deleted==1:
return False
db_teacher.is_deleted=1 # 标记为1逻辑删除
db.commit() # 提交事务
return True
@staticmethod
def update(db: Session,teacher_id:int,teacher_data: TeacherUpdate):
"""
更新用户信息(只更新传入的非空字段)
:param db: 数据库会话
:param teacher_data: 包含要更新字段的 Pydantic 模型
:return: 更新后的 User 对象,如果用户不存在则返回 None
"""
# 只更新客户端显式传入的字段(exclude_unset=True 排除未设置的字段,不排除设置了None的字段)
update_data = teacher_data.model_dump(exclude_unset=True) # 返回要更新字段的字典
db_teacher=TeacherDAO.inspect_teacher_id_unq(db, teacher_id)
for key, value in update_data.items():
setattr(db_teacher, key, value) # 动态设置属性
db.commit() # 提交事务
db.refresh(db_teacher) # 刷新对象,获取 onupdate 时间等
return db_teacher
@staticmethod
def get_all(db: Session, skip: int = 0, limit: int = 100):
"""
获取所有用户(支持分页,不显示软删除)
:param db: 数据库会话
:param skip: 偏移量(跳过前 skip 条,从skip+1条开始返回)
:param limit: 最大返回条数
:return: 用老师对象列表
"""
return db.query(Teacher).filter(Teacher.is_deleted==0).offset(skip).limit(limit).all()