12 KiB
学生就业信息管理系统 —— 就业模块项目文档
一、模块概述
本模块是「学生就业信息管理系统」的核心业务模块,负责管理学生就业状态的全生命周期。围绕就业信息(Employments)、公司信息(Company)、地址信息(Address)三张核心表,并与学生表(students)、班级表(classes)建立外键关联,提供增删改查(CRUD)与统计分析接口。
技术栈:
| 项 | 选型 |
|---|---|
| Web 框架 | FastAPI |
| ORM | SQLAlchemy 2.x |
| 数据库 | MySQL 8.x(驱动 PyMySQL) |
| 数据校验 | Pydantic v2 |
| 服务启动 | Uvicorn |
二、目录结构
student_manage_system/
├── main.py # 程序入口:注册全模块路由、建表(__main__ 中执行)
├── databases.py # 根数据库配置:engine_all / Base_all / Session / get_db
└── stu_jiuye/ # 就业模块业务包
├── main.py # 路由组装(Shtudent_Jiuye);独立自测 app
├── database.py # 模块级数据库配置(engine / Base / Session / get_db)
├── model.py # ORM 模型:Employments / Company / Address
├── request.py # Pydantic 请求体 / 响应体模型
├── dao.py # 数据访问层(纯数据库操作)
└── CURD_api.py # 路由层(API 接口定义)
分层职责:
| 层 | 文件 | 职责 |
|---|---|---|
| 路由层 | CURD_api.py | 接收 HTTP 请求,参数校验,调用 DAO,返回响应 |
| 数据访问层 | dao.py | 封装 SQLAlchemy 查询与事务,向上提供函数 |
| 模型层 | model.py | 定义表结构与外键关系 |
| 校验层 | request.py | 定义请求体 / 响应体的字段与类型 |
| 配置层 | database.py | 数据库 URL、引擎、Session 工厂 |
三、数据表设计
1. Employments(就业信息表)
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | Integer | PK, 自增 | 主键 |
| stuid | Integer | FK → students.id | 学生 ID |
| class_id | Integer | FK → classes.id | 班级 ID |
| company_id | Integer | FK → Company.id, 可空 | 就业公司 |
| address_id | Integer | FK → Address.id, NOT NULL | 就业地址 |
| employment_salary | Integer | 可空 | 就业薪资 |
| employment_open_time | DATE | 可空 | 就业开放时间 |
| offer_recived_time | DATE | 可空 | Offer 下发时间 |
| create_time | DateTime | default=now | 创建时间 |
| update_time | DateTime | default=now, onupdate=now | 更新时间 |
| is_deleted | Integer | default=0 | 软删除标记(0 正常 / 1 已删) |
2. Company(公司表)
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | Integer | PK, 自增 | 主键 |
| employment_company | String(50) | NOT NULL | 公司名称 |
| create_time | DateTime | default=now | 创建时间 |
| update_time | DateTime | default=now, onupdate=now | 更新时间 |
| is_deleted | Integer | default=0 | 软删除标记 |
3. Address(地址表)
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | Integer | PK, 自增 | 主键 |
| somewhere | String(50) | NOT NULL | 地址区域,如"深圳市南山区" |
| create_time | DateTime | default=now | 创建时间 |
| update_time | DateTime | default=now, onupdate=now | 更新时间 |
| is_deleted | Integer | default=0 | 软删除标记 |
表关系图
students (1) ───< (N) Employments (N) >─── (1) Company
classes (1) ───< (N) | (N) >─── (1) Address
- 一个学生可有多个就业记录,一条就业记录对应一个学生(通过 stuid 关联学生表)
- 一条就业记录对应一个公司(company_id)与一个地址(address_id)
- 通过多表 JOIN 可从就业记录直接获取学生姓名、班级名称、公司名称与地址信息
设计说明:姓名/班级不冗余,走 JOIN 获取
与"在就业表冗余学生姓名"的方案不同,本模块选择通过 stuid、class_id 外键关联学生表与班级表,查询时动态 JOIN 获取姓名与班级名。代价是查询多一次 JOIN;好处是学生姓名/班级变更后无需同步,数据天然一致。
四、API 功能清单(CRUD)
接口定义于 stu_jiuye/CURD_api.py 的 CURD 路由,由根 main.py 以 Shtudent_Jiuye 挂载。
📌 新增(Create)
| 方法 | 路径 | 功能 | 请求体 |
|---|---|---|---|
| POST | /emp/company/address | 新增地址区域 | AddRequest |
| POST | /emp/company | 新增公司 | CompRequest |
| POST | /emp | 新增学生就业信息 | PostRequest |
注意:由于外键依赖,建议按 Address → Company → Employments 的顺序添加。
📌 查询(Read)
| 方法 | 路径 | 功能 | 查询参数 |
|---|---|---|---|
| GET | /emp | 多条件查询就业信息 | sname、class_id、employment_company、min_salary、max_salary、somewhere、employment_open_start、employment_open_end、offer_recived_start、offer_recived_end(全部可选,均不传则查询全部) |
就业薪资 Top5、就业时长、平均就业时长等统计接口已迁移至统计分析模块(StatCalc):
/statcalc/top、/statcalc/job、/statcalc/avgjob。
📌 更新(Update)
| 方法 | 路径 | 功能 | 参数 |
|---|---|---|---|
| PUT | /emp?id=X | 修改就业信息 | Query:id;Body:PostRequest(支持部分字段更新) |
📌 删除(Delete)
| 方法 | 路径 | 功能 | 参数 |
|---|---|---|---|
| DELETE | /emp/{id} | 软删除就业信息 | Path:id |
删除说明:本模块采用软删除(is_deleted = 1),数据不会从物理表中移除,便于审计与恢复。
五、核心流程示例
查询流程(GET /emp)
前端 → CURD_api.get_stuinfo()
↓ 收集 10 个可选查询条件
↓ 调用 get_emp_dao()
↓ DAO 五表 OUTER JOIN:Employments + Students + ClassInfo + Company + Address
↓ 动态拼接 filter(姓名/班级/公司/薪资范围/地址/时间范围)
↓ 统一过滤 is_deleted = 0
↓ 返回 list[dict](含学生姓名、班级名称、公司、区域、薪资、时间)
↓ 结果为空 → 404「名单不存在」
添加流程(POST /emp)
前端 → CURD_api.add_stuinfo()
↓ p.model_dump() 转 dict
↓ add_employment_dao()
↓ o.pop('id' / 'create_time' / 'update_time' / 'is_deleted') 去掉自增主键与自动字段
↓ Employments(**o) 实例化
↓ db.add → db.commit → db.refresh
↓ 失败 → db.rollback → 返回 500
更新流程(PUT /emp?id=X)
前端 → CURD_api.updata_stuinfo()
↓ 请求体排除未传字段(exclude_unset)
↓ 为空 → 400「没有需要更新的字段」
↓ update_emp_dao() 按 id 执行 update
↓ 影响 0 行 → 404「未找到对应记录」
删除流程(DELETE /emp/{id})
前端 → CURD_api.delete_stuinfo()
↓ delete_emp_dao() 按 id 执行 UPDATE is_deleted = 1(软删除)
↓ 影响 0 行 → 500「没有删除」
六、项目亮点
-
清晰的分层架构 路由(CURD_api.py)、数据访问(dao.py)、模型(model.py)、校验(request.py)各司其职,便于单元测试与维护。
-
全链路软删除 Employments、Company、Address 三张表均有
is_deleted字段,删除统一走UPDATE is_deleted = 1,数据可追溯、可恢复;查询时统一过滤is_deleted == 0。 -
动态多条件组合查询
get_emp_dao使用链式 filter 动态拼接查询条件,任一条件为空自动跳过,一个接口覆盖 10 种查询维度(姓名/班级/公司/薪资区间/地址/开放时间区间/Offer 时间区间)。 -
统一时间戳审计 所有表均带
create_time/update_time,onupdate=datetime.now让修改自动记录时间,为审计、报表提供数据基础。 -
请求体与响应体分离 request.py 为每类资源定义独立请求体(PostRequest / CompRequest / AddRequest)与响应体(EmpResponse / CompResponse / AddResponse),前端契约清晰,Swagger 自动生成接口文档。
-
多表 JOIN 关联查询 就业记录与学生、班级、公司、地址四张表通过外键关联,一次查询即可返回完整就业信息,无需前端二次请求。
-
外键约束保证数据完整性 stuid / class_id / company_id / address_id 全部建立外键,杜绝"就业记录指向不存在学生/公司"的脏数据。
七、待添加的新功能 与 已知问题
🎯 短期(可快速落地)
| 功能 | 说明 | 涉及改动 |
|---|---|---|
| 分页查询 | /emp 支持 page / page_size,返回 total 与 items | dao.py 加 .offset().limit(),request.py 加分页请求体 |
| 薪资区间校验 | 确保 min_salary <= max_salary | request.py 加 @model_validator |
| 数据去重 | 同一学生同一公司只保留一条有效就业记录 | add_employment_dao 前置查询 + 唯一约束 |
| 级联删除 | 删公司/地址时同步软删其下就业记录 | dao.py 加级联更新逻辑 |
| 外键存在性校验 | 新增时校验 stuid / company_id / address_id 真实存在,给出明确错误 | dao.py 前置查询 |
🚀 中期(需要设计)
| 功能 | 说明 |
|---|---|
| 批量导入 | 支持 Excel/CSV 批量导入就业信息 |
| 数据导出 | 查询结果一键导出为 Excel |
| JWT 鉴权 | 管理员 / 普通用户角色分离,保护写接口 |
| 操作日志 | 记录每一次增删改操作的操作人与时间 |
| Alembic 迁移 | 用 Alembic 管理表结构变更,告别手动 DROP TABLE |
🌟 长期(数据价值)
| 功能 | 说明 |
|---|---|
| 就业数据看板 | 按班级/公司/薪资维度统计,前端可视化 |
| 薪资分布分析 | 直方图、分位数、同比环比 |
| 就业率追踪 | 结合学生表计算班级/专业就业率 |
| 缓存层 | Redis 缓存 Top5、统计类接口 |
| 异步任务 | Celery 处理导入/导出等耗时任务 |
八、运行方式
# 1. 安装依赖
pip install fastapi uvicorn sqlalchemy pymysql pydantic python-dotenv
# 2. 配置数据库(项目根目录 .env 中 DB_USER / DB_PASSWORD / DB_HOST / DB_PORT / DB_NAME)
# 3. 启动服务(根入口,含全模块)
python main.py
# 或
uvicorn main:app --host 127.0.0.1 --port 59000 --reload
# 4. 单独调试就业模块
uvicorn stu_jiuye.main:app --host 127.0.0.1 --port 12395 --reload
# 5. 访问 Swagger 文档
http://127.0.0.1:59000/docs
九、注意事项
- 表结构变更需删表重建:
Base.metadata.create_all(engine)只建不改,模型加字段后需 DROP TABLE 或引入 Alembic。 - 建表时机:当前建表逻辑在根
main.py的__main__块中执行;直接用uvicorn main:app启动时不会建表,全新环境需先执行一次python main.py(或后续将建表移入 FastAPI lifespan)。 - 添加顺序有外键依赖:先建学生/班级/公司/地址,再添加就业记录;Employments 的 stuid / class_id / company_id / address_id 均受外键约束。
- 软删除后查询自动过滤:
get_emp_dao已统一过滤is_deleted == 0,被删除的记录不会再出现在列表里。 - 删除接口用 Path 参数:
DELETE /emp/{id},不要写成/emp?id=X。 - echo=True 仅限开发:生产环境请关掉,避免刷屏与性能损耗。