1. 项目背景与核心需求
奖学金评定评优系统是高校学生管理工作中不可或缺的一环。传统的人工评审方式存在效率低下、主观性强、数据统计困难等问题。我在参与某高校信息化建设时,发现他们仍在使用Excel表格进行奖学金评定,经常出现公式错误、数据重复录入等问题,评审过程平均需要2-3周才能完成。
基于Python的解决方案能有效解决以下痛点:
- 评审标准复杂多样(成绩占比、社会实践、科研成果等权重不同)
- 多维度数据整合困难(需要对接教务系统、学工系统等)
- 评审流程透明度不足(学生无法实时查看进度)
- 历史数据难以追溯(往届评审结果查询不便)
2. 技术选型对比分析
2.1 Django vs Flask框架选择
在开发初期,我对两个主流框架进行了详细对比测试:
| 特性 | Django | Flask |
|---|---|---|
| 开发速度 | 快速(自带Admin后台) | 中等(需自行搭建) |
| 数据库支持 | ORM完善(支持迁移) | SQLAlchemy扩展 |
| 模板系统 | 内置Django Template | Jinja2(更灵活) |
| 适用场景 | 全功能Web应用 | 轻量级API服务 |
| 学习曲线 | 较陡峭(约定优于配置) | 平缓(更自由) |
最终选择Django的核心原因:
- 内置的Admin后台可直接用于评审管理
- 自带的用户认证系统满足多角色需求(学生/辅导员/管理员)
- 强大的ORM支持多数据源关联查询
- 自动生成的管理界面减少前端工作量
实际开发建议:如果评审规则特别复杂需要频繁调整,可以考虑Flask+SQLAlchemy的灵活组合。但在标准评审场景下,Django的开发效率优势明显。
2.2 PyCharm开发环境配置
推荐使用PyCharm Professional版(社区版缺少Django模板支持):
bash复制# 创建虚拟环境(必须)
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
# 安装核心依赖
pip install django==4.2 psycopg2-binary # PostgreSQL驱动
pip install django-import-export==3.3.0 # 数据导入导出
关键配置步骤:
- 在PyCharm中设置Django支持:File > Settings > Languages & Frameworks > Django
- 启用Django模板语法高亮
- 配置Database工具连接(推荐PostgreSQL)
- 安装Python代码检查工具(Pylint+Black)
3. 系统架构设计
3.1 核心数据模型
python复制# models.py
class Student(models.Model):
sno = models.CharField(primary_key=True, max_length=20) # 学号
name = models.CharField(max_length=50)
department = models.ForeignKey('Department', on_delete=models.PROTECT)
class Scholarship(models.Model):
SCHOLARSHIP_TYPES = (
('national', '国家奖学金'),
('enterprise', '企业奖学金'),
('school', '校级奖学金')
)
name = models.CharField(max_length=100)
type = models.CharField(max_length=20, choices=SCHOLARSHIP_TYPES)
quota = models.PositiveIntegerField() # 名额限制
class Application(models.Model):
STATUS_CHOICES = (
('draft', '草稿'),
('submitted', '已提交'),
('approved', '学院通过'),
('rejected', '已拒绝')
)
student = models.ForeignKey(Student, on_delete=models.CASCADE)
scholarship = models.ForeignKey(Scholarship, on_delete=models.PROTECT)
apply_time = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES)
score = models.DecimalField(max_digits=5, decimal_places=2, null=True)
3.2 评审流程状态机
实现多级审批工作流:
python复制# signals.py
@receiver(post_save, sender=Application)
def handle_application_status(sender, instance, **kwargs):
if instance.status == 'submitted':
# 自动触发院系审核
notify_department_auditor(instance)
elif instance.status == 'approved':
# 进入校级评审池
add_to_school_review_pool(instance)
4. 核心功能实现
4.1 动态评分规则引擎
解决不同奖学金类型评分标准差异问题:
python复制# scoring.py
class ScoringEngine:
def __init__(self, rule_config):
self.rules = json.loads(rule_config)
def calculate(self, student):
total = 0
for rule in self.rules['criteria']:
weight = rule['weight']
# 动态调用对应的评分方法
method = getattr(self, f'score_{rule["field"]}')
total += method(student) * weight
return total
def score_gpa(self, student):
return student.transcript.gpa * 10
def score_research(self, student):
return student.papers.count() * 2
4.2 批量导入优化
处理Excel数据导入的性能问题:
python复制# admin.py
@admin.register(Student)
class StudentAdmin(ImportExportModelAdmin):
resource_class = StudentResource
list_display = ('sno', 'name', 'department')
def get_import_form(self):
# 重写导入表单增加预处理
form = super().get_import_form()
form.custom_field = forms.FileField(
label='选择Excel文件',
help_text='请确保第一行包含表头'
)
return form
5. 典型问题解决方案
5.1 并发提交冲突
使用select_for_update解决多人同时提交时的数据竞争:
python复制def submit_application(student_id, scholarship_id):
with transaction.atomic():
scholarship = Scholarship.objects.select_for_update().get(pk=scholarship_id)
if scholarship.quota <= Application.objects.filter(
scholarship=scholarship,
status__in=['approved', 'submitted']
).count():
raise ValidationError("该奖学金申请名额已满")
Application.objects.create(
student_id=student_id,
scholarship_id=scholarship_id,
status='submitted'
)
5.2 成绩数据同步
定时任务同步教务系统数据:
python复制# management/commands/sync_grades.py
class Command(BaseCommand):
def handle(self, *args, **options):
from_time = timezone.now() - timedelta(days=1)
updated = sync_from_jw_system(since=from_time)
self.stdout.write(f"成功同步{updated}条成绩记录")
# 设置Celery定时任务
@app.task
def scheduled_sync():
call_command('sync_grades')
6. 部署优化实践
6.1 性能调优配置
python复制# settings.py
# 数据库连接池配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'CONN_MAX_AGE': 300, # 连接复用
'OPTIONS': {
'connect_timeout': 3,
}
}
}
# 缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
6.2 安全防护措施
- CSRF防护加强:
python复制CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Strict'
- SQL注入防护:
python复制# 永远使用参数化查询
Student.objects.raw('SELECT * FROM student WHERE name = %s', [name])
- 敏感操作日志:
python复制class AuditLogMiddleware:
def process_request(self, request):
if request.method in ['POST', 'DELETE']:
log_action(
user=request.user,
action=request.path,
metadata=request.GET.dict()
)
7. 实际开发经验总结
- 数据库设计教训:
- 早期没有考虑评审记录版本控制,导致规则修改后历史记录无法追溯
- 解决方案:新增ApplicationVersion模型与原始记录关联
- 性能优化技巧:
- 列表页N+1查询问题:使用select_related/prefetch_related
python复制Application.objects.select_related(
'student__department'
).prefetch_related(
'student__papers'
)
- 调试技巧:
- 使用django-debug-toolbar分析查询
- 日志记录关键操作:
python复制LOGGING = {
'handlers': {
'audit_file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': '/var/log/scholarship_audit.log',
}
}
}
- 测试建议:
- 使用factory_boy创建测试数据
- 对评分规则进行参数化测试
python复制@pytest.mark.parametrize('gpa,expected', [
(3.5, 35),
(4.0, 40)
])
def test_score_gpa(gpa, expected):
student = StudentFactory(transcript__gpa=gpa)
assert engine.score_gpa(student) == expected
