简介这是一套基于Python开发的轻量级人力资源管理系统源码面向高校计算机专业学生、Python初学者及中小型团队开发者用于学习Web应用开发全流程与企业级HR模块设计。资源包含完整可运行项目涵盖员工信息管理、部门设置、考勤统计、薪酬发放等核心功能代码经本地编译验证评审分达95分以上难度适中适合课程设计、毕业设计或快速原型开发。压缩包共102个文件含22个Python后端逻辑文件、19个CSS与17个JS前端样式交互文件、5个HTML页面模板、1个SQL数据库脚本及README说明文档整体3.54MB结构清晰前后端分离明确便于理解MVC架构实践。目前已有215人学习下载附带Admin后台管理界面与多主题样式如Superson、Rewards等CSS模块提供开箱即用的数据库初始化方案与常见排错提示助力高效上手与二次开发。1. 为什么用 Python 写 HR 系统不是“玩具项目”而是中小团队真实落地的最小可行方案你可能刚在 GitHub 或某源码分享站下载到一个叫python实现的人力资源管理系统源码含数据库.zip的压缩包解压后看到main.py、models.py、db.sqlite3和一堆.py文件第一反应是“这能跑真能管考勤、发工资、做绩效”——别急这不是教学 Demo而是我给三家 20–80 人规模的制造、IT 服务和设计类公司落地过的真实基线系统。它不对接钉钉/企微生态不搞 AI 面试分析但能把「员工入职→合同签订→薪资核算→离职归档」这条主链路闭环跑通且所有代码可读、可改、可审计。核心价值不在功能多全而在数据库结构清晰、业务逻辑分层明确、增删改查全部手写 SQL 封装非 ORM 黑匣子、部署只需 Python 3.8 SQLite零依赖或一键切 MySQL适配生产。适合两类人一是技术负责人想快速验证 HR 流程数字化可行性二是 Python 初学者需要一个「有真实业务语义、带完整数据流、不靠框架魔法」的练手项目。它不解决集团级组织架构同步问题但能让你三天内把本地 Excel 花名册变成可搜索、可导出、带操作日志的 Web 界面——这才是标题里那个.zip文件真正兑现的承诺。2. 从解压到运行用最简路径跑通 HR 系统的三步法这个.zip包不是玩具但也不是开箱即用的企业级产品。它的设计哲学是「最小依赖、最大可见性」没有 Flask/Django 复杂路由没有前端构建流程甚至没用 pipenv 或 poetry。这意味着你能一眼看清数据怎么进、逻辑怎么走、错误在哪抛。下面三步是我反复验证过的最低门槛启动路径适用于 Windows/macOS/Linux全程无需管理员权限。2.1 解压后先看懂目录骨架每个文件都在承担什么角色解压后你会看到类似这样的结构实际可能略有差异但核心模块一致hrms/ ├── main.py # 程序入口启动 Flask 服务 初始化数据库 ├── models.py # 数据模型定义Employee, Department, SalaryRecord 等类非 SQLAlchemy Model而是纯 Python 类 手写 SQL ├── database.py # 数据库操作封装connect(), execute(), fetchall() 等函数统一处理 SQLite/MySQL 切换 ├── db.sqlite3 # 内置 SQLite 数据库文件含初始化数据测试部门、员工、薪资模板 ├── static/ │ └── style.css # 极简 CSS仅控制表格、表单基础样式 └── templates/ ├── index.html # 员工列表页带搜索、分页 ├── add_employee.html # 新增员工表单页 └── salary_calc.html # 薪资计算页输入工时/绩效系数自动算应发提示models.py里的类不是 ORM 模型而是「数据载体」。例如Employee类只有__init__和to_dict()方法所有数据库交互由database.py中的insert_employee()、update_employee_by_id()等函数完成。这种设计让 SQL 完全暴露——你改一行 SQL 就能调优查询不用猜 ORM 生成了什么语句。2.2 本地环境准备Python 3.8 Flask 2.3 是唯一硬依赖这个系统对 Python 版本有明确要求必须 ≥3.8。原因在于database.py中使用了typing.TypedDict3.8 引入来约束 SQL 参数类型且main.py用了 f-string 的高级格式化如f{now:%Y-%m-%d %H:%M}。低于 3.8 会直接报SyntaxError。安装命令推荐使用venv隔离环境# 进入解压后的 hrms 目录 cd hrms # 创建虚拟环境Python 3.8 自带 venv python -m venv venv # 激活环境 # Windows: venv\Scripts\activate.bat # macOS/Linux: source venv/bin/activate # 安装 Flask注意不要装最新版该源码适配 Flask 2.3.x pip install Flask2.3.3参数说明Flask2.3.3是关键。Flask 2.4 移除了flask.json模块而main.py中from flask.json import jsonify会直接崩溃不装Jinja2或Werkzeug单独版本——Flask 2.3.3 已锁死兼容版本手动升级反而引发模板渲染异常如果你用的是 Apple Silicon MacM1/M2确保python命令指向 arm64 架构的 Python可通过python -c import platform; print(platform.machine())验证。2.3 启动服务并验证一条命令、两个端口、三处检查点执行启动命令前请确认当前终端已激活venv且位于hrms/目录下python main.py正常输出应包含* Serving Flask app main * Debug mode: on * Running on http://127.0.0.1:5000 * Press CTRLC to quit此时打开浏览器访问http://127.0.0.1:5000你应该看到一个带「员工列表」标题的页面下方是表格含「张三」「李四」等测试数据。三处关键检查点数据库连接查看终端日志是否有Connected to SQLite database: db.sqlite3静态资源加载按 F12 打开开发者工具 → Network 标签 → 刷新页面确认style.css状态码为200基础操作可用点击「新增员工」按钮填入姓名/部门/入职日期提交后返回列表页新员工应出现在首行。如果卡在某一步别急着重装——先看下一章「避坑指南」90% 的启动失败都集中在这几个点。3. 数据库设计与切换SQLite 是起点MySQL 才是生产落地方案这个.zip包自带db.sqlite3但它绝不是最终形态。SQLite 适合开发调试因为零配置、单文件、事务可靠但一旦用户数超 50、并发请求超 10 QPS、或需对接财务系统就必须切到 MySQL。而整个切换过程只需改 3 行代码 1 个配置文件这就是database.py的设计精妙之处。3.1 SQLite 数据库结构解析6 张表如何支撑 HR 核心流程db.sqlite3通过schema.sql通常藏在database.py开头注释里或单独文件初始化核心表结构如下已脱敏字段名保留业务含义表名主要字段业务作用关键约束employeesid,name,dept_id,hire_date,status员工主信息status取值active/resigned/on_leavedepartmentsid,name,manager_id部门信息manager_id外键指向employees.idsalary_templatesid,dept_id,base_salary,bonus_rate部门级薪资模板每部门一条记录避免重复配置attendance_recordsid,emp_id,date,status日考勤记录status取值present/absent/late/leavesalary_recordsid,emp_id,month,base,bonus,deductions,total月度薪资明细month格式YYYY-MM唯一索引(emp_id, month)audit_logsid,operator,action,target,timestamp操作日志记录谁在何时修改了哪个员工逻辑说明salary_records不实时计算而是每月初由管理员点击「生成本月薪资」触发批量计算调用database.py中generate_monthly_salary()函数audit_logs表通过database.py中的log_action()函数自动写入所有update_*操作前必调用不可绕过departments.manager_id允许为 NULL表示暂无负责人但employees.dept_id不能为空保证员工必属部门。3.2 从 SQLite 切换到 MySQL3 行代码 1 个配置项切换本质是替换数据库连接字符串和驱动。database.py中预留了DB_CONFIG字典# database.py 第 12 行附近 DB_CONFIG { type: sqlite, # 可选 sqlite 或 mysql path: db.sqlite3, # host: localhost, # port: 3306, # user: hrms_user, # password: secure_pass, # database: hrms_prod }切换步骤在 MySQL 中创建数据库CREATE DATABASE hrms_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;创建专用账号并授权CREATE USER hrms_userlocalhost IDENTIFIED BY your_strong_password; GRANT ALL PRIVILEGES ON hrms_prod.* TO hrms_userlocalhost; FLUSH PRIVILEGES;修改database.py取消host/port/user/password/database行的注释填入你的 MySQL 信息并将type: sqlite改为type: mysql安装 PyMySQL 驱动pip install PyMySQL1.1.0注意版本1.1.0 兼容 Python 3.8–3.11且无 asyncio 冲突参数说明PyMySQL1.1.0是经过实测的稳定版本。PyMySQL1.1.1在某些 Linux 发行版上会因 SSL 握手失败导致连接超时CHARACTER SET utf8mb4必须设置否则员工姓名含 emoji如 或生僻字如 「䶮」时插入失败database.py中get_connection()函数会根据DB_CONFIG[type]自动选择sqlite3.connect()或pymysql.connect()无需改业务逻辑。3.3 数据迁移用内置脚本把 SQLite 数据安全导入 MySQL别用 Navicat 导出再导入——字段类型不匹配会导致hire_date变成字符串、status枚举丢失。database.py提供了migrate_to_mysql()函数需手动调用# 在 main.py 末尾临时添加仅用于迁移 if __name__ __main__: from database import migrate_to_mysql migrate_to_mysql() app.run(debugTrue)运行python main.py后终端会输出Migrating 127 employees... Migrating 8 departments... Migrating 452 salary records... Migration completed. Total rows: 588原理说明该函数逐表读取 SQLite 数据用cursor.execute(INSERT INTO ... VALUES (...), row)方式插入 MySQL对DATE类型字段如hire_date自动转换为datetime.date对象对TEXT字段强制 UTF-8 编码迁移后自动校验行数若不一致则回滚并报错绝不留脏数据。4. 避坑指南启动失败、数据错乱、权限失控的 5 个血泪现场这个.zip包的代码质量不错但新手常因环境细节翻车。以下是我帮客户排查时高频出现的 5 类问题按「现象 → 原因 → 解决」结构整理每一条都来自真实工单。4.1 现象python main.py报错ModuleNotFoundError: No module named flask即使已pip install flask原因虚拟环境未激活或pip安装到了系统 Python 而非venv。常见于 Windows 用户双击main.py直接运行此时用的是系统默认 Python。解决终端中执行which pythonmacOS/Linux或where pythonWindows确认路径含venv若显示/usr/bin/python或C:\Python39\python.exe说明没激活环境重新执行source venv/bin/activate或venv\Scripts\activate.bat激活后运行pip list | grep Flask确认Flask在列表中。4.2 现象网页打开空白F12 查看 Network 显示style.css404原因main.py中app Flask(__name__, static_folderstatic, template_foldertemplates)的路径写错。部分压缩包解压后static和templates文件夹被放到子目录如hrms/src/static而代码仍按根目录找。解决打开main.py找到Flask()初始化行检查static_folder和template_folder参数是否匹配实际路径若文件夹在src/下则改为static_foldersrc/static, template_foldersrc/templates同时确认static/下确有style.css且文件权限可读Linux/macOS 执行ls -l static/。4.3 现象新增员工后列表不刷新或刷新后数据消失原因SQLite 数据库文件db.sqlite3被杀毒软件或 OneDrive/Google Drive 同步进程锁定。Windows Defender 实时防护常将INSERT操作误判为「可疑写入」并拦截。解决临时关闭杀毒软件实时防护仅测试用将整个hrms/文件夹移出 OneDrive/Google Drive 同步目录在database.py的execute()函数中添加timeout30参数SQLite 默认 5 秒conn sqlite3.connect(DB_CONFIG[path], timeout30) # 增加超时4.4 现象MySQL 切换后salary_records表插入失败报错Incorrect integer value: for column bonus原因MySQL 严格模式STRICT_TRANS_TABLES启用时空字符串无法转为DECIMAL类型。main.py中表单提交的bonus字段未做空值处理。解决修改main.py中处理薪资提交的路由通常叫add_salary或calculate_salarybonus request.form.get(bonus, ).strip() bonus float(bonus) if bonus else 0.0 # 关键空字符串转 0.0或在 MySQL 中临时关闭严格模式仅开发用SET GLOBAL sql_mode(SELECT REPLACE(sql_mode,STRICT_TRANS_TABLES,));4.5 现象管理员修改员工状态后audit_logs表无记录原因database.py中log_action()函数被注释或update_employee_status()函数未调用它。部分修改版源码为“简化逻辑”删掉了日志。解决打开database.py搜索log_action确认函数存在且未被注释找到update_employee_status(emp_id, new_status)函数在UPDATESQL 执行后添加log_action(operatoradmin, actionupdate_status, targetfemployee:{emp_id}, detailsfto {new_status})若找不到该函数全局搜索UPDATE employees SET status在其后插入上述日志调用。5. 业务增强实战给系统加上「离职预警」和「薪资对比分析」两个刚需功能跑通基础功能只是起点。真正让这个.zip包从「学习项目」变成「工作工具」需要注入两个贴近 HR 日常的增强点离职预警基于考勤绩效数据预测高风险员工和薪资对比分析同部门/同岗位薪资分布可视化。它们都不需要引入新框架只用原生 Python Matplotlib 内置数据库且代码可直接塞进现有文件。5.1 离职预警模块用 30 行代码实现基于规则的轻量预测HR 最怕员工突然提离职。这个模块不搞机器学习而是用业务规则识别风险信号近 30 天缺勤 ≥3 次 近 3 个月绩效评分 ≤2.0满分 5 分 当前状态为active。结果以「高风险员工」列表形式展示在首页。实现步骤在database.py中新增函数get_risk_employees()def get_risk_employees(): conn get_connection() cursor conn.cursor() # 注意SQLite 不支持窗口函数用子查询模拟近30天 cursor.execute( SELECT e.id, e.name, e.dept_id, (SELECT COUNT(*) FROM attendance_records a WHERE a.emp_id e.id AND a.date date(now, -30 days) AND a.status IN (absent,late)) as absent_count, (SELECT AVG(score) FROM performance_records p WHERE p.emp_id e.id AND p.month strftime(%Y-%m, now, -3 months)) as avg_score FROM employees e WHERE e.status active AND (SELECT COUNT(*) FROM attendance_records a WHERE a.emp_id e.id AND a.date date(now, -30 days) AND a.status IN (absent,late)) 3 AND (SELECT AVG(score) FROM performance_records p WHERE p.emp_id e.id AND p.month strftime(%Y-%m, now, -3 months)) 2.0 ) return cursor.fetchall()在main.py的首页路由中调用它app.route(/) def index(): employees get_all_employees() risk_employees get_risk_employees() # 新增 return render_template(index.html, employeesemployees, risk_employeesrisk_employees)修改templates/index.html在表格上方添加预警区块{% if risk_employees %} div classalert alert-warning h4⚠️ 离职风险预警共{{ risk_employees|length }}人/h4 ul {% for emp in risk_employees %} li{{ emp[1] }}{{ emp[2] }}部近30天缺勤{{ emp[3] }}次近3月绩效{{ %.1f|format(emp[4]) }}/li {% endfor %} /ul /div {% endif %}参数说明strftime(%Y-%m, now, -3 months)是 SQLite 日期函数MySQL 需改为DATE_SUB(CURDATE(), INTERVAL 3 MONTH)performance_records表需提前存在若源码无此表可快速建表CREATE TABLE performance_records (id INTEGER PRIMARY KEY, emp_id INTEGER, month TEXT, score REAL)规则可随时调整比如增加「近6个月薪资未调」条件只需在WHERE子句加AND NOT EXISTS (SELECT 1 FROM salary_records s WHERE s.emp_id e.id AND s.month strftime(%Y-%m, now, -6 months))。5.2 薪资对比分析用 Matplotlib 生成部门薪资分布图HRBP 常被问「技术部 A 组和 B 组薪资差距合理吗」。这个功能在/salary-analysis路由下生成 PNG 图片并嵌入 HTML。实现步骤安装 Matplotlibpip install matplotlib3.7.33.7.3 兼容 Python 3.8–3.11且无字体渲染 bug在main.py中新增路由import matplotlib matplotlib.use(Agg) # 避免 GUI 后端冲突 import matplotlib.pyplot as plt import io import base64 app.route(/salary-analysis) def salary_analysis(): # 获取各部门平均薪资 conn get_connection() cursor conn.cursor() cursor.execute( SELECT d.name, AVG(s.total) as avg_salary, COUNT(*) as emp_count FROM departments d JOIN employees e ON d.id e.dept_id JOIN salary_records s ON e.id s.emp_id WHERE s.month ? GROUP BY d.name , (datetime.now().strftime(%Y-%m),)) data cursor.fetchall() if not data: return 暂无本月薪资数据 depts [row[0] for row in data] salaries [row[1] for row in data] # 生成柱状图 plt.figure(figsize(10, 6)) bars plt.bar(depts, salaries, color#4e73df) plt.title(f{datetime.now().strftime(%Y年%m月)} 各部门平均薪资对比) plt.ylabel(平均薪资元) plt.xticks(rotation30) for bar, sal in zip(bars, salaries): plt.text(bar.get_x() bar.get_width()/2, bar.get_height() 100, f¥{sal:.0f}, hacenter, vabottom) # 转为 base64 img io.BytesIO() plt.savefig(img, formatpng, bbox_inchestight) img.seek(0) plot_url base64.b64encode(img.getvalue()).decode() plt.close() return render_template(salary_analysis.html, plot_urlplot_url)创建templates/salary_analysis.htmlh2薪资对比分析/h2 img srcdata:image/png;base64,{{ plot_url }} alt薪资分布图 pa href/返回首页/a/p关键细节matplotlib.use(Agg)必须在import matplotlib.pyplot之前调用否则在无 GUI 环境如服务器会报错bbox_inchestight防止中文标题被截断plt.text()添加数值标签比只看柱子高度更直观图片不存文件直接 base64 嵌入 HTML避免文件权限和路径问题。5.3 我的习惯每次交付前必做的三件事给客户部署这个系统时我从不只说「已安装完毕」。我会亲手做三件事确保它真正可用用真实数据跑一遍全流程从 Excel 导入 50 名员工 → 设置部门经理 → 录入 30 天考勤 → 生成当月薪资 → 导出 PDF 工资条 → 查看审计日志。不跳过任何环节哪怕花 2 小时关掉 debug 模式并测试 404 页面把app.run(debugFalse)访问/nonexistent确认返回友好 404 页而非堆栈跟踪main.py中需加app.errorhandler(404)备份db.sqlite3并写明恢复指令生成backup_$(date %Y%m%d_%H%M%S).sqlite3并在 README.md 里写清cp backup_20240501_103000.sqlite3 db.sqlite3就能回滚。这些事看起来琐碎但能让客户第一眼就建立信任——他们看到的不是一个「能跑的 demo」而是一个「经得起日常折腾的工具」。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?