在高校数字化校园建设中,教务管理系统是核心枢纽,而选课与成绩录入模块则是直接关系到学生学业体验的关键功能。本文将从源码层面,拆解这两个模块的核心逻辑与实现思路,帮助开发者快速理解并搭建类似功能。
🎯 选课模块核心源码逻辑
选课模块的核心需求是实现学生自主选择课程、系统实时校验冲突并锁定名额,同时支持管理员后台配置课程容量与选课规则。以下是关键代码模块的解析:
1. 课程数据模型设计
from django.db import models
from django.contrib.auth.models import User
class Course(models.Model):
course_id = models.CharField(max_length=20, unique=True, verbose_name="课程编号")
name = models.CharField(max_length=100, verbose_name="课程名称")
teacher = models.ForeignKey(User, on_delete=models.CASCADE, related_name="taught_courses", verbose_name="授课教师")
credit = models.FloatField(verbose_name="学分")
capacity = models.IntegerField(verbose_name="选课容量")
enrolled_count = models.IntegerField(default=0, verbose_name="已选人数")
start_time = models.DateTimeField(verbose_name="开课时间")
end_time = models.DateTimeField(verbose_name="结课时间")
def __str__(self):
return f"{self.course_id} - {self.name}"
class StudentCourse(models.Model):
student = models.ForeignKey(User, on_delete=models.CASCADE, related_name="selected_courses", verbose_name="学生")
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name="enrolled_students", verbose_name="课程")
select_time = models.DateTimeField(auto_now_add=True, verbose_name="选课时间")
class Meta:
unique_together = ("student", "course")
代码解析:
- 采用Django ORM设计数据模型,通过
Course类存储课程基础信息,StudentCourse类记录学生选课关联关系 - 通过
unique_together约束确保学生无法重复选择同一门课程 - 实时维护
enrolled_count字段,避免超容量选课
2. 选课冲突校验逻辑
from django.utils import timezone
from django.db.models import Q
def check_time_conflict(student, new_course):
# 获取学生已选课程的时间范围
existing_courses = StudentCourse.objects.filter(student=student).values_list('course__start_time', 'course__end_time')
for start, end in existing_courses:
# 时间冲突判断:新课程时间与已有课程时间存在重叠
if (new_course.start_time < end) and (new_course.end_time > start):
return True
return False
def select_course(student, course_id):
try:
course = Course.objects.get(course_id=course_id)
except Course.DoesNotExist:
return "课程不存在"
# 校验课程容量
if course.enrolled_count >= course.capacity:
return "课程已满员"
# 校验时间冲突
if check_time_conflict(student, course):
return "选课时间冲突"
# 原子操作:避免并发选课导致超容
with transaction.atomic():
course.enrolled_count += 1
course.save()
StudentCourse.objects.create(student=student, course=course)
return "选课成功"
代码解析:
- 通过
check_time_conflict函数判断新选课程与已选课程的时间是否重叠 - 采用数据库事务(
transaction.atomic())确保选课操作的原子性,解决并发场景下的超容问题 - 分层校验逻辑:依次检查课程存在性、容量限制、时间冲突,最后执行选课操作
📝 成绩录入模块核心源码逻辑
成绩录入模块需要支持教师批量录入成绩、系统自动计算绩点,同时提供学生成绩查询与申诉入口。以下是核心功能的实现代码:
1. 成绩数据模型设计
class Grade(models.Model):
student = models.ForeignKey(User, on_delete=models.CASCADE, related_name="grades", verbose_name="学生")
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name="grades", verbose_name="课程")
score = models.FloatField(verbose_name="成绩")
gpa = models.FloatField(blank=True, null=True, verbose_name="绩点")
submit_time = models.DateTimeField(auto_now_add=True, verbose_name="录入时间")
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
class Meta:
unique_together = ("student", "course")
def save(self, *args, **kwargs):
# 自动计算绩点
if self.score >= 90:
self.gpa = 4.0
elif self.score >= 85:
self.gpa = 3.7
elif self.score >= 82:
self.gpa = 3.3
elif self.score >= 78:
self.gpa = 3.0
elif self.score >= 75:
self.gpa = 2.7
elif self.score >= 72:
self.gpa = 2.3
elif self.score >= 68:
self.gpa = 2.0
elif self.score >= 64:
self.gpa = 1.5
elif self.score >= 60:
self.gpa = 1.0
else:
self.gpa = 0.0
super().save(*args, **kwargs)
代码解析:
- 通过重写
save方法,在成绩录入时自动计算绩点,减少业务逻辑的冗余 - 采用
unique_together约束确保同一学生同一课程只能有一条成绩记录 - 记录成绩的提交与更新时间,便于追溯成绩修改历史
2. 教师批量录入成绩功能
import pandas as pd
from django.http import JsonResponse
def batch_import_grades(request, course_id):
if request.method != "POST":
return JsonResponse({"status": "error", "message": "仅支持POST请求"})
try:
course = Course.objects.get(course_id=course_id)
except Course.DoesNotExist:
return JsonResponse({"status": "error", "message": "课程不存在"})
# 验证当前用户是否为课程教师
if request.user != course.teacher:
return JsonResponse({"status": "error", "message": "无权限录入该课程成绩"})
file = request.FILES.get("grade_file")
if not file:
return JsonResponse({"status": "error", "message": "请上传成绩文件"})
# 读取Excel文件
df = pd.read_excel(file)
required_columns = ["学号", "成绩"]
if not all(col in df.columns for col in required_columns):
return JsonResponse({"status": "error", "message": "文件格式错误,需包含'学号'和'成绩'列"})
success_count = 0
error_count = 0
error_messages = []
for index, row in df.iterrows():
student_id = row["学号"]
score = row["成绩"]
try:
student = User.objects.get(username=student_id)
# 检查学生是否选过该课程
if not StudentCourse.objects.filter(student=student, course=course).exists():
error_messages.append(f"行{index+2}: 学生{student_id}未选该课程")
error_count += 1
continue
# 更新或创建成绩记录
grade, created = Grade.objects.update_or_create(
student=student,
course=course,
defaults={"score": score}
)
success_count += 1
except User.DoesNotExist:
error_messages.append(f"行{index+2}: 学生{student_id}不存在")
error_count += 1
return JsonResponse({
"status": "success",
"success_count": success_count,
"error_count": error_count,
"error_messages": error_messages
})
代码解析:
- 支持教师上传Excel文件批量录入成绩,提高工作效率
- 多层权限校验:验证教师身份、学生选课状态,确保成绩录入的合法性
- 详细的错误反馈机制,帮助教师快速定位并修正录入错误
🚀 性能优化与安全建议
- 选课模块优化:
- 采用Redis缓存热门课程的剩余容量,减少数据库查询压力
- 对选课请求进行限流,防止恶意刷课行为
- 实现选课排队机制,在课程容量满额时允许学生排队等待退课名额
- 成绩模块安全:
- 对成绩录入接口添加操作日志,记录每次成绩修改的人员与时间
- 学生成绩查询接口采用加密传输,防止数据泄露
- 实现成绩申诉流程,支持学生提交申诉申请,管理员后台审核处理
💡 总结
选课与成绩录入模块作为教务管理系统的核心功能,其源码设计需要兼顾业务逻辑的严谨性与用户体验的流畅性。通过本文的源码解析,开发者可以快速理解这两个模块的核心实现思路,并根据实际需求进行定制化开发。在实际项目中,还需要结合学校的具体业务规则,进一步完善系统的功能与性能。