Merge remote-tracking branch 'origin/lon_students_merge_code_test' into lon_students_merge_code_test

This commit is contained in:
2026-09-22 23:35:16 +08:00
10 changed files with 220 additions and 40 deletions
+2 -2
View File
@@ -11,7 +11,7 @@ tea_api = APIRouter()
@tea_api.post('/tea',response_model=TeaResponse,summary='新增老师',description='输入新增的老师信息,除去姓名外可以为空')
def add_tea(tea: NewTeaRequest=Depends(),db=Depends(get_db)):
r = add_tea_dao(tea.model_dump(),db)
r = add_tea_dao(tea.model_dump(exclude_unset=True),db)
if not r:
raise HTTPException(status_code=500,detail='添加失败!')
return TeaResponse(totals=1,data=tea.model_dump())
@@ -48,7 +48,7 @@ def delete_other_tea_dao1(t:TeaRequest=Depends(),db=Depends(get_db)):
@tea_api.post('/subject',summary='新增科目',description='输入新增的科目')
def add_sub(t:SubRequest=Depends(),db=Depends(get_db)): #开启会话窗口
r = add_subject_dao(t.model_dump(),db=db)
if not r:
if r=='已存在':
raise HTTPException(status_code=500,detail='科目已存在')
return TeaResponse(totals=len(r), data=r)
+6 -4
View File
@@ -128,15 +128,17 @@ def add_subject_dao(t,db):
try:
t1 = db.query(Sub).filter(Sub.name == t.get('name')).first()
if t1:
print('科目已存在')
raise Exception('科目已存在')
return'已存在'
s1 = Sub(**t)
db.add(s1)
db.commit()
return '添加成功'
except Exception as e:
return '[s1]'
except InterruptedError as e:
db.rollback()
print('失败的原因',e)
return False
except Exception as e:
db.rollback()
return f'{e}'
+1
View File
@@ -24,4 +24,5 @@ def get_db():
yield db
finally:
db.close()
#建表
Base.metadata.create_all(engine1)
-3
View File
@@ -16,17 +16,14 @@ class Tea(Base_all):
,autoincrement=True
,comment='id')
name = Column(String(50)
,nullable=False
,comment='姓名')
sex = Column(Enum(Gender),default='未知'
,comment='性别')
class_id = Column(Integer
,nullable=False
,comment='班级id')
phone = Column(String(50))
subject_id = Column(Integer
, ForeignKey('subject.id')
,nullable=False
,comment='教学科目')
home_place = Column(String(50)
,comment='家乡')
+4 -4
View File
@@ -7,7 +7,7 @@ class TeaRequest(BaseModel):
name: str|None = None
sex: Gender|None = None
class_id: int | None = None
sub: str|None = None
subject_id: str|None = None
phone: str | None
home_place: str|None = None
collage: str|None = None
@@ -22,7 +22,7 @@ class NewTeaRequest(BaseModel):
name: str | None = None
sex: Gender|None = None
class_id: int | None = None
sub: str | None = None
subject_id: int | None = None
home_place: str | None = None
phone: str | None = Field(default=None, min_length=11, max_length=11)
collage: str | None = None
@@ -35,7 +35,7 @@ class NewTeaRequest1(BaseModel):
name: str | None = None
sex: Gender|None = None
class_id: int | None = None
sub: str | None = None
subject_id: int | None = None
home_place: str | None = None
phone: str | None = Field(default=None, min_length=11, max_length=11)
collage: str | None = None
@@ -45,4 +45,4 @@ class NewTeaRequest1(BaseModel):
specialty: str | None = None
class SubRequest(BaseModel):
name: str | None = None
name: str
+33
View File
@@ -0,0 +1,33 @@
#scores模块解释
##项目层
web框架:FastAPI(生成接口)
ORM:sqlalchemy
校验:MYSQL(通过PyMysql驱动)
运行:uvicorn,端口12346
用FastAPI显露HTTP接口 ,对MysQL的scores表进行一个增,删,改,查的动作,删除是软删除,
api是接口层,成绩信息的增加,删除,更新,查询
dao是数据操作层,查询get_scores_dao
更新add_scores_dao
增加update_scores_dao
删除delete_scores_dao
统计查询80分以上的get_top_students_dao
查询连续两次不及格的get_failing_students_dao
班级平均分get_class_avg_dao
model是数据库表模型层,字段信息 id *pk*
sid 链接学生表的学生ID
cid 链接班级表的班级ID
num 考试序次
score 考试成绩
t_subject 链接科目表的科目ID
create_date 创建数据的时间
update_date 更新数据的是时间
is_deleted 逻辑删除
deleted_date 删除的时间
schema是请求体和响应体模型层, 查询的ScoreQuery
更新,增加,删除的ScoreRequest
databases是数据库定义配置文件, 链接引擎对象db_url,链接地址engine,
建表的基类Base,数据库会话管理Session
会话实例def get_db()
main是主程序文件,将配置文件的接口导入,创建接口运行
+1 -1
View File
@@ -93,7 +93,7 @@ def delete_stuinfo( #删除模块
): #根据id选择对象
rows = delete_emp_dao(id, db) #调用删除函数
if not rows:
raise HTTPException(status_code=500, detail='没有删除!') #失败返回错误信息
raise HTTPException(status_code=404, detail='未找到该就业记录!') #失败返回错误信息
return {'code': 200, 'totals': rows, 'detail': '删除成功'} #成功返回信息
'''
+10 -10
View File
@@ -85,19 +85,19 @@ def get_emp_dao( #获取学生
# ,page
# ,page_size
): #根据选择条件获取信息
q = db.query(Employments,Company.employment_company,Address.somewhere) \
.outerjoin(Students, Students.id == Employments.stuid) \
.outerjoin(ClassInfo, ClassInfo.id == Employments.class_id)\
.outerjoin(Company,Employments.company_id==Company.id)\
.outerjoin(Address,Employments.address_id==Address.id)\
.filter(Employments.is_deleted == 0) #连接公司表和地址表,筛选未被删除信息
q = (db.query(Employments,Company.employment_company,Address.somewhere)
.outerjoin(Students, Students.id == Employments.stuid)
.outerjoin(ClassInfo, ClassInfo.id == Employments.class_id)
.outerjoin(Company,Employments.company_id==Company.id)
.outerjoin(Address,Employments.address_id==Address.id)
.filter(Employments.is_deleted == 0)) #连接公司表和地址表,筛选未被删除信息
# if stuid:
# q = q.filter( Employments.id == stuid )
if sname: #根据学生姓名筛选
q = q.filter( Students.name == sname )
if class_id:
q = q.filter(ClassInfo.id == class_id)
q = q.filter(Employments.class_id == class_id)
if somewhere:
q = q.filter(Address.somewhere.like(f'%{somewhere}%'))
if employment_company: #根据公司姓名筛选
@@ -119,7 +119,7 @@ def get_emp_dao( #获取学生
if r:
return [ {"id": i.id,
'学生姓名':sname,
'学生班级编号':class_id,
'学生班级编号':i.class_id,
"公司": employment_company or '未就业',
"公司区域":somewhere or '-',
"薪资":i.employment_salary or '-',
@@ -128,8 +128,8 @@ def get_emp_dao( #获取学生
# , "创建时间": i.create_time,
# "更新时间": i.update_time,
# "是否删除":i.is_deleted
} for i,sname,class_id,employment_company,somewhere in r ] #返回信息列表
} for i,sname,employment_company,somewhere in r ] #返回信息列表
return {"code": 200, "totals": len(r), "data": r}
def delete_emp_dao(id,db): #删除函数
try:
+161 -14
View File
@@ -16,48 +16,195 @@ ORM:sqlalchemy
## main:学生管理系统的主程序文件、测试接口
1. 下面所有配置文件的接口全部导入并建表
2. 创建fastapi接口并本地运行
2. 创建合并接口APIRouter
3. 创建fastapi接口并本地运行
## databases:链接数据库配置文件
1. 链接本地mysql,实例化mysql,创建引擎,创建基类,实例化数据库会话
2. 创建函数,调用数据库会话
3. 因为后期多代码合并,每个人的databases都不同链接也不同,所以导入了.env文件
1. 这样在每个人有差异的数据可以直接保存在本地,不用反复同步相互覆盖了
2. 另外一个原因就是model层大家建表要使用同一个基类
1. 所以接入了.env文件随时入参
2. 这样更加方便,而且高频同步和拉取也不用重新配置
## 分层代码书写顺序:
1. model层:
1. 确认你的业务需要哪些字段
2. 确认小组的字段名、表名、库名一致
3. 确认主键、唯一键、字段数据类型、外键等关键字内容
2. 请求体
1. 搞清楚业务需求,需要用到哪些字段
2. 增删改查的具体逻辑
3. api
1. 写好接收变量
2. 装饰器设定
3. 输出规则
4. 一次写好基本上就不会再改了
4. dao
1. 工作量最大的层,所有的业务逻辑都写在这里面
2. 所有的业务逻辑都在这个层里
## api.students_api:接口文件
### 学生表students的功能接口:
1. 学生信息的查询
1. 仅保存入参标量,代码都在逻辑层,建好了基本不用修改,方便维护
2. 学生信息的新增
1. 仅保存入参标量,代码都在逻辑层,建好了基本不用修改,方便维护
3. 学生信息的更新
1. 仅保存入参标量,代码都在逻辑层,建好了基本不用修改,方便维护
4. 学生信息的逻辑删除
1. 仅保存入参标量,代码都在逻辑层,建好了基本不用修改,方便维护
## dao.students_dao:数据筛选文件
### 数据库的逻辑筛选文件:
1. 查询:get_student_dao
1. 筛选所有非空内容,过滤逻辑删除数据,输出学生完整字段
2. 新增:add_student_dao
1. 关键字段限制
2. 过滤各种报错,反馈报错问题
3. 无报错即可全部插入
4. 注意逻辑删除的数据,其实也会占用唯一键,所以有唯一键重复时,直接拉出旧数据进行清空翻新。
3. 更新:update_student_dao
1. 主要过滤掉没有输入的字段,除非输入才可以被覆盖,不能每次更新清空全部内容
2. 唯一字段过滤,比如电话号码,在业务逻辑上电话号码不能重复
4. 逻辑删除:delete_student_dao
1. 逻辑删除可以用所有字段进行精确或者范围删除
2. 但是不可以全为空删除我的整个库
## model.students_model:数据库建表文件
1. 数据表建表代码
2. 字段信息: sid **PK**
, student_name
, student_phone
, class_name
, job_open_time
, offer_issue_time
, company_name
, salary
, create_date
, update_date
, is_deleted
, deleted_date
, **待建FK:** class_id/teacher_id/score_id/company_id/
2. 字段信息: `id`:***PK***
`num`:***UNI***
`name`
`age`
`sex`:*ENUM*
`home_Place`
`college`
`specialty`
`enrollment_time`
`graduate_time`
`education`:*ENUM*
***外键字段***
`class_id`:***FK***
`advisor_id`:***FK***
***额外字段***
`phone`:***UNI***
***通用字段***
`create_date`
`update_date`
`is_deleted`
`deleted_date`
## schema.students_request:请求体、数据过滤
请求体根据业务要求有不同调整,方便后续维护和更改需求
1. 查询:StudentsQuery
1. 所有字段都可以进行查询
2. 随便填哪个都可以进行精确查询或者范围查询
3. 全为空即查询全部
2. 新增:StudentsResponse
1. 新增有必填项、不可重复项等,保证数据干净
3. 更新:StudentsUpdate
1. 以ID作为查询字段,更新其他内容
2. 会过滤掉重复值
4. 逻辑删除:StudentsDelete
1. 所有字段都可以进行删除
2. 随便填哪个都可以进行精确删除或者范围删除
3. 不可全字段为空
## StatCalc:统计分析模块
除了没有model以外没有什么太大的区别
## 学生管理系统修改报错记录
### 1. 合并修改记录:
1. main.py
1. 所有子模块中的main新增了APIRouter,用来拉到主main进行运行
2. stu_jiuye
1. stu_jiuye\main.py
1. 新增为加粗倾斜处
2. from ***sut_jiuye***.文件名 import 调用名
2. CURD_api.py
1. 新增为加粗倾斜处
2. from ***sut_jiuye***.文件名 import 调用名
2. databases.py
1. 所有人的db_url账号密码IP端口和名称全部存入了.env文件
2. 导入了load_dotenv进行调用
1. from dotenv import load_dotenv
2. load_dotenv( )
3. DB_USER = os.getenv("DB_USER", "root")
4. DB_PASSWORD = os.getenv("DB_PASSWORD", "")
5. DB_HOST = os.getenv("DB_HOST", "localhost")
6. DB_PORT = os.getenv("DB_PORT", "3306")
7. DB_NAME = os.getenv("DB_NAME", "student_manage_system")
3. 修改了部分url名称,自行检查
3. class文件夹下导入修改
1. 新增为加粗倾斜处
1. from ***class_management***.文件名 import 调用名
1. 改动文件:
1. class_management_api.py
2. class_management_dao.py
3. class_management_model.py
### 2. 合并完成
1. 新增.env文件,设置好账号密码等
1. 可以一次运行创建好所有表格
2. 但是注意,没办法创建库,也就是student_manage_system
3. 如果没有建库的话会报错
2. 表外键写完之后,可以用SQL语句删除所有表
1. 再重新运行***main.py***文件
1. 这个main.py特指最外层的运行主程序main.py
### 3. 分支测试
1. 阶段完成后
1. 如果不擅长保存版本,可以在自己的分支下面再建新分支
2. 方便切换版本和查询bug,理解逻辑,以免修改后bug更多了
3. 完成后可以将子分支变基到主线
4. 变基(覆盖)完成后可以继续使用子分支进行修改整合
2. 注意云端仓库,没有修改的文件是不会反复上传的
1. 所以看距离时间最近的基本都是被修改过的
2. 可以用来进行版本对比
### 4. 外键创建
1. 外键必须要来自同一个基类,不然会报错
1. 新增主程序的databases.py文件,统一基类
### 5. 外键报错
1. 在新建字段时,依赖主表的外键必须要已经建立,不然在提交时都会报错
2. 所以新增接口的报错逻辑需要特别优化,将各个阶段可能报错的内容都捕获下来
## hermes agent协作内容:
### 1. 测试数据脚本 — init_test_data.py
向数据库插入了完整的测试数据,没有修改任何原有项目文件:
数据类型
数量
科目 6 门(Python程序设计、数据结构、数据库原理等)
教师 6 位(张伟、李芳、王强、陈静、刘洋、赵敏)
班级 3 个(CS2401、CS2402、AI2501)
学生 20 名(涵盖3个班级,男女各半)
成绩 120 条(每名学生6门课,含部分不及格记录)
公司 5 家(字节跳动、阿里巴巴、腾讯、华为、百度)
就业信息 8 条(含薪资、offer时间等)
### 2. 前端页面 — frontend/index.html
单文件完整前端,包含:
首页:问候 Banner + 快捷卡片(查课表/查成绩/校园卡/报修)+ 校园动态信息流
学生管理:表格列表、搜索过滤、新增/编辑/删除(含二次确认弹窗)
成绩查询:学期切换 Tab、成绩卡片展示、Chart.js 柱状图
教师管理:教师列表、搜索、新增
就业管理:就业信息列表、状态标签(已就业/待就业)
个人中心:蓝色背景头像区 + 功能菜单列表
交互特性:
✅ 卡片点击缩放反馈(95% 回弹,150ms)
✅ 页面切换从右侧滑入(300ms)
✅ 删除二次确认弹窗
✅ Toast 提示(成功/失败/信息)
✅ 鼠标悬停按钮/卡片颜色加深、阴影加深
✅ 隔行变色表格 + 表头排序
启动后端后直接浏览器打开 frontend/index.html 即可使用。
+2 -2
View File
@@ -30,7 +30,7 @@ class Students(Base_all):
, comment='年龄'
, nullable=False)
sex = Column(Enum(SexEnum, values_callable=lambda e: [i.value for i in e])
sex = Column(Enum(SexEnum)
, comment='性别'
, nullable=False)
@@ -49,7 +49,7 @@ class Students(Base_all):
graduate_time = Column(DATETIME
, comment='毕业时间')
education = Column(Enum(EducationEnum, values_callable=lambda e: [i.value for i in e])
education = Column(Enum(EducationEnum)
, comment='学历'
, nullable=True)