1. 项目背景与需求分析
学生请销假系统是高校信息化建设中的基础模块,也是教务管理数字化转型的重要切入点。传统纸质请假流程存在审批周期长、记录难追溯、数据难统计等痛点。我们团队基于Python+Vue技术栈开发的这套系统,实现了从请假申请到审批归档的全流程电子化。
从技术选型角度看,这个项目涉及几个核心需求:
- 前端需要响应式界面,适配PC和移动端(Vue.js)
- 后端需要处理复杂业务逻辑和权限控制(Django/Flask)
- 需要数据库持久化存储(ORM)
- 开发过程需要高效调试(PyCharm)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈选型与对比
2.1 前端框架:为什么选择Vue.js
Vue作为渐进式框架,在中小型管理系统开发中具有明显优势:
- 组件化开发模式,便于请假表单、审批流程等模块的复用
- 双向数据绑定简化了表单处理逻辑
- Vue CLI提供的脚手架工具快速初始化项目
- Element UI组件库完美匹配管理系统UI需求
对比React和Angular,Vue的学习曲线更平缓,适合高校信息化团队的技术储备现状。
2.2 后端框架:Django vs Flask的抉择
我们最终选择Django作为主要后端框架,但在部分微服务模块使用了Flask:
| 特性 | Django优势 | Flask优势 |
|---|---|---|
| 开发效率 | 自带Admin后台、ORM、认证等全套方案 | 轻量级,适合快速开发简单接口 |
| 性能 | 中等,适合常规业务场景 | 更轻量,适合高并发简单接口 |
| 学习成本 | 较高,需要理解Django设计理念 | 较低,可以按需添加功能 |
| 适用场景 | 复杂业务系统 | 微服务、简单API接口 |
| 扩展性 | 通过第三方包扩展 | 通过插件机制灵活扩展 |
在请假系统中,核心业务模块使用Django:
- 利用Django Admin快速搭建审批后台
- 使用Django ORM处理复杂的数据关系
- 内置的用户认证系统满足权限控制需求
而一些辅助功能如短信通知接口,则采用Flask实现,保持灵活性。
3. 系统架构设计
3.1 前后端分离架构
系统采用典型的前后端分离架构:
code复制前端(Vue.js) <-- REST API --> 后端(Django/Flask)
↑ ↑
浏览器访问 数据库(MySQL)
这种架构的优势在于:
- 前后端可以并行开发
- 前端可以独立部署,不影响后端服务
- 清晰的API契约定义接口规范
3.2 数据库设计
主要实体关系:
- 学生(Student)
- 教师(Teacher)
- 请假单(LeaveApplication)
- 审批记录(ApprovalRecord)
使用Django的models.py定义:
python复制class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
student_id = models.CharField(max_length=20)
department = models.CharField(max_length=100)
class LeaveApplication(models.Model):
LEAVE_TYPES = (
('sick', '病假'),
('private', '事假'),
('official', '公假')
)
student = models.ForeignKey(Student, on_delete=models.CASCADE)
leave_type = models.CharField(max_length=20, choices=LEAVE_TYPES)
start_time = models.DateTimeField()
end_time = models.DateTimeField()
reason = models.TextField()
status = models.CharField(max_length=20, default='pending')
class ApprovalRecord(models.Model):
application = models.ForeignKey(LeaveApplication, on_delete=models.CASCADE)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
comment = models.TextField(blank=True)
decision = models.CharField(max_length=10)
timestamp = models.DateTimeField(auto_now_add=True)
3.3 API接口设计
遵循RESTful规范设计主要API端点:
| 端点 | 方法 | 描述 |
|---|---|---|
| /api/leave-applications | GET | 获取请假列表 |
| /api/leave-applications | POST | 提交新请假申请 |
| /api/leave-applications/ | GET | 获取特定请假详情 |
| /api/approvals | POST | 教师审批操作 |
| /api/statistics | GET | 获取请假统计信息 |
4. 核心功能实现
4.1 请假申请流程
前端Vue组件结构:
html复制<template>
<div class="leave-apply">
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="请假类型" prop="leaveType">
<el-select v-model="form.leaveType">
<el-option label="病假" value="sick"></el-option>
<el-option label="事假" value="private"></el-option>
</el-select>
</el-form-item>
<!-- 其他表单字段 -->
<el-button @click="submit">提交</el-button>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
form: {
leaveType: '',
startTime: '',
endTime: '',
reason: ''
},
rules: {
leaveType: [{ required: true, message: '请选择类型', trigger: 'blur' }],
// 其他验证规则
}
}
},
methods: {
async submit() {
try {
await this.$refs.form.validate()
const res = await this.$http.post('/api/leave-applications', this.form)
this.$message.success('提交成功')
} catch (err) {
this.$message.error(err.message)
}
}
}
}
</script>
后端Django视图处理:
python复制from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class LeaveApplicationView(APIView):
def post(self, request):
serializer = LeaveApplicationSerializer(data=request.data)
if serializer.is_valid():
serializer.save(student=request.user.student)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4.2 审批工作流实现
使用Django的信号机制实现审批状态变更通知:
python复制from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import ApprovalRecord
@receiver(post_save, sender=ApprovalRecord)
def update_application_status(sender, instance, created, **kwargs):
if created:
application = instance.application
application.status = 'approved' if instance.decision == 'approve' else 'rejected'
application.save()
# 发送通知
notify_student(application.student, instance.decision)
4.3 权限控制方案
结合Django的权限系统和自定义装饰器:
python复制from functools import wraps
from django.http import JsonResponse
def teacher_required(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
if not hasattr(request.user, 'teacher'):
return JsonResponse({'error': '无权访问'}, status=403)
return view_func(request, *args, **kwargs)
return _wrapped_view
@teacher_required
def approval_view(request):
# 审批逻辑
pass
5. 开发环境配置
5.1 PyCharm项目设置
-
创建Django项目:
- 使用PyCharm的Django模板初始化项目
- 配置Python解释器(建议使用虚拟环境)
-
前端项目集成:
- 在项目根目录创建
frontend文件夹存放Vue代码 - 配置运行配置(Run Configuration)启动前端服务
- 在项目根目录创建
-
数据库配置:
python复制DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'leave_system', 'USER': 'root', 'PASSWORD': 'yourpassword', 'HOST': 'localhost', 'PORT': '3306', } }
5.2 前后端联调技巧
-
解决跨域问题:
python复制# settings.py INSTALLED_APPS = [ ... 'corsheaders', ] MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', ] CORS_ORIGIN_WHITELIST = [ 'http://localhost:8080', ] -
API文档生成:
使用drf-yasg自动生成Swagger文档:python复制from drf_yasg import openapi from drf_yasg.views import get_schema_view schema_view = get_schema_view( openapi.Info( title="请假系统API", default_version='v1', ), public=True, ) urlpatterns = [ ... path('swagger/', schema_view.with_ui('swagger', cache_timeout=0)), ]
6. 部署方案
6.1 生产环境部署
前端部署:
bash复制npm run build
# 生成的dist目录部署到Nginx
# Nginx配置示例
server {
listen 80;
server_name yourdomain.com;
location / {
root /path/to/dist;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend_server;
proxy_set_header Host $host;
}
}
后端部署:
bash复制# 使用Gunicorn启动Django
gunicorn --workers 4 --bind 0.0.0.0:8000 yourproject.wsgi:application
# 使用Supervisor管理进程
[program:leave_system]
command=/path/to/venv/bin/gunicorn --workers 4 yourproject.wsgi:application
directory=/path/to/project
user=youruser
autostart=true
autorestart=true
6.2 性能优化建议
-
数据库优化:
- 为常用查询字段添加索引
- 使用
select_related和prefetch_related减少查询次数
-
缓存策略:
python复制# settings.py CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379/1', } } # 视图缓存示例 from django.views.decorators.cache import cache_page @cache_page(60 * 15) def leave_statistics(request): # 统计逻辑 pass
7. 常见问题与解决方案
7.1 跨域会话保持问题
现象:前端登录后,后续请求未携带认证信息
解决方案:
python复制# settings.py
CORS_ALLOW_CREDENTIALS = True
SESSION_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SECURE = True
# 前端axios配置
axios.defaults.withCredentials = true
7.2 时区处理不一致
统一使用UTC时间存储,前端展示时转换:
python复制# settings.py
TIME_ZONE = 'UTC'
USE_TZ = True
# 前端处理
import moment from 'moment'
moment.utc(serverTime).local().format('YYYY-MM-DD HH:mm')
7.3 文件上传与下载
使用Django处理文件上传:
python复制# models.py
class Attachment(models.Model):
application = models.ForeignKey(LeaveApplication, on_delete=models.CASCADE)
file = models.FileField(upload_to='attachments/%Y/%m/%d/')
# settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
8. 项目扩展方向
-
移动端适配:
- 开发微信小程序版本
- 使用Vue Native或React Native开发跨平台App
-
智能审批:
- 集成机器学习模型,对请假事由进行自动分类和初步审核
- 基于历史数据预测可能的虚假请假
-
数据可视化:
- 使用ECharts实现请假数据多维分析
- 院系、班级、个人维度的请假趋势图表
-
消息推送:
- 集成短信、邮件、站内信多种通知方式
- 审批结果实时推送
在开发过程中,PyCharm的Django支持插件和Vue.js插件极大提升了开发效率。特别是它的数据库工具可以直接查看和编辑数据,调试时非常方便。
