基于Django实现的智慧校园考试系统-自动组卷算法实现
目录
- 一.🦁 项目概述
- 1.1 技术栈
- 1.2 安装与运行
- 二.🦁 演示系统流程
- 2.1 管理员端
- 2.2 学生端
- 2.3 自动组卷算法实现
- 1. 核心思路
- 2. 随机与去重
- 三.🦁 API接口文档
- 3.1 用户管理
- 3.2 题库管理
- 3.3 考试管理
- 3.4 成绩管理
项目定制业务:前端、后端(Python、Java、C#、PHP)、算法(深度学习、机器学习)、大数据(Hadoop、hive、spark)、小程序等项目,
无论是商用还是学校项目(毕业设计、课程设计等),都可咨询,价格合理,服务周全!
如果你有需要,添加vx:732708009
一.🦁 项目概述
基于Django开发的智慧校园考试系统后端API,采用前后端分离架构,提供RESTful风格接口,涵盖用户管理、题库管理、考试管理和成绩管理等核心功能模块。首先,用户管理模块支持学生和管理员两种角色,提供用户注册与登录(JWT认证)、个人信息管理。其次,题库管理模块支持多种试题类型,如单选题、判断题、填空题、简答题,实现试题的CRUD操作、智能组卷算法、试题分类标签管理及难度系数设置。然后,考试管理模块涵盖考试创建、考生报名与审核、在线考试等功能,提供考试场次管理。最后,成绩管理模块实现了自动评分(客观题)、成绩统计分析、提供成绩查询、成绩分布可视化以及错题分析和历史成绩对比等功能。
1.1 技术栈
- Python 3.8+
- Django 4.2
- Django REST Framework
- MySQL
1.2 安装与运行
- 克隆项目:gitcode、Githup
- 安装依赖:
pip install -r requirements.txt - 配置数据库:修改
settings.py中的数据库配置 - 运行服务器:
python manage.py runserver
二.🦁 演示系统流程
2.1 管理员端
- 登录

2. 仪表板

3. 用户管理

4. 题库管理


5. 考试管理

6. 试卷管理
- 手动组卷

- 自动组卷

- 成绩管理

2.2 学生端
- 首页

- 考试列表

- 查看成绩

- 个人中心

- 考试页面


2.3 自动组卷算法实现
1. 核心思路
- 先创建一条考试记录 Exam (校验通过后保存)。
- 对每个题型,分别按难度从题库查询题目列表。
- 如果某个难度的题数不够,直接返回错误。
- 若题数足够,就用 random.sample 在题目列表里随机抽取指定数量。
- 把抽到的题目逐条保存成 ExamQuestion ,与该考试关联。
- 最后返回这次考试的基本信息和总题数。
2. 随机与去重
- random.sample 在同一题型+难度范围内不会重复抽同一题
- 不会出现跨题型重复,因为查询条件包含 question_type
- 如果 question_types 传入有重复值,会去重
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def generate_exam_paper(request):# 获取考试基本信息exam_name = request.data.get('exam_name')start_time = request.data.get('start_time')end_time = request.data.get('end_time')duration = request.data.get('duration')# 获取题目配置easy_count = int(request.data.get('easy_count', 0))medium_count = int(request.data.get('medium_count', 0))hard_count = int(request.data.get('hard_count', 0))question_types = request.data.get('question_types', [])# 创建考试exam_data = {'exam_name': exam_name,'start_time': start_time,'end_time': end_time,'duration': duration}serializer = ExamSerializer(data=exam_data)if not serializer.is_valid():return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)exam = serializer.save()# 为每种题型按难度分布生成题目selected_questions = []total_questions = 0# 遍历每种题型for question_type in question_types:# 获取当前题型不同难度的题目easy_questions = list(Question.objects.filter(difficulty_level='easy', question_type=question_type))medium_questions = list(Question.objects.filter(difficulty_level='medium', question_type=question_type))hard_questions = list(Question.objects.filter(difficulty_level='hard', question_type=question_type))# 检查当前题型的题目数量是否足够if easy_count > 0 and len(easy_questions) < easy_count:return Response({"error": f"{question_type}类型的简单题目不足,需要 {easy_count} 道,实际只有 {len(easy_questions)} 道"}, status=status.HTTP_400_BAD_REQUEST)if medium_count > 0 and len(medium_questions) < medium_count:return Response({"error": f"{question_type}类型的中等题目不足,需要 {medium_count} 道,实际只有 {len(medium_questions)} 道"}, status=status.HTTP_400_BAD_REQUEST)if hard_count > 0 and len(hard_questions) < hard_count:return Response({"error": f"{question_type}类型的困难题目不足,需要 {hard_count} 道,实际只有 {len(hard_questions)} 道"}, status=status.HTTP_400_BAD_REQUEST)# 为当前题型随机选择题目if easy_count > 0:selected_questions.extend(random.sample(easy_questions, easy_count))total_questions += easy_countif medium_count > 0:selected_questions.extend(random.sample(medium_questions, medium_count))total_questions += medium_countif hard_count > 0:selected_questions.extend(random.sample(hard_questions, hard_count))total_questions += hard_count# 添加题目到考试for question in selected_questions:ExamQuestion.objects.create(exam=exam, question=question)# 返回包含题目数量的考试信息exam_data = ExamSerializer(exam).dataexam_data['question_count'] = total_questionsreturn Response({"message": f"成功自动生成试卷,包含 {total_questions} 道题目(每种题型:简单{easy_count}道,中等{medium_count}道,困难{hard_count}道)","exam": exam_data}, status=status.HTTP_201_CREATED)
三.🦁 API接口文档
3.1 用户管理
- 注册用户
-
URL:
/api/users/register/ -
方法: POST
-
请求体:
{"username": "用户名","password": "密码","role": "admin或student" } -
响应:
{"user_id": 1,"username": "用户名","role": "admin或student","created_at": "创建时间" }
- 用户登录
-
URL:
/api/users/login/ -
方法: POST
-
请求体:
{"username": "用户名","password": "密码" } -
响应:
{"token": "JWT令牌","user": {"user_id": 1,"username": "用户名","role": "admin或student"} }
- 获取当前用户信息
-
URL:
/api/users/current/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
{"user_id": 1,"username": "用户名","role": "admin或student","created_at": "创建时间" }
- 获取所有用户
-
URL:
/api/users/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
[{"user_id": 1,"username": "用户名","role": "admin或student","created_at": "创建时间"} ]
- 获取特定用户
-
URL:
/api/users/{user_id}/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
{"user_id": 1,"username": "用户名","role": "admin或student","created_at": "创建时间" }
- 更新用户
-
URL:
/api/users/{user_id}/update/ -
方法: PUT
-
请求头:
Authorization: Bearer {token} -
请求体:
{"username": "新用户名","password": "新密码","role": "新角色" } -
响应:
{"user_id": 1,"username": "新用户名","role": "新角色","created_at": "创建时间" }
- 删除用户
- URL:
/api/users/{user_id}/delete/ - 方法: DELETE
- 请求头:
Authorization: Bearer {token} - 响应: 204 No Content
3.2 题库管理
- 添加题目
-
URL:
/api/questions/add/ -
方法: POST
-
请求头:
Authorization: Bearer {token} -
请求体:
{"content": "题目内容","question_type": "choice/true_false/fill_in_blank/essay","difficulty_level": "easy/medium/hard" } -
响应:
{"question_id": 1,"content": "题目内容","question_type": "choice/true_false/fill_in_blank/essay","difficulty_level": "easy/medium/hard","created_at": "创建时间" }
- 获取所有题目
-
URL:
/api/questions/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
[{"question_id": 1,"content": "题目内容","question_type": "choice/true_false/fill_in_blank/essay","difficulty_level": "easy/medium/hard","created_at": "创建时间"} ]
- 获取特定题目
-
URL:
/api/questions/get/{question_id}/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
{"question_id": 1,"content": "题目内容","question_type": "choice/true_false/fill_in_blank/essay","difficulty_level": "easy/medium/hard","created_at": "创建时间" }
- 更新题目
-
URL:
/api/questions/update/{question_id}/ -
方法: PUT
-
请求头:
Authorization: Bearer {token} -
请求体:
{"content": "新题目内容","question_type": "新题目类型","difficulty_level": "新难度级别" } -
响应:
{"question_id": 1,"content": "新题目内容","question_type": "新题目类型","difficulty_level": "新难度级别","created_at": "创建时间" }
- 删除题目
- URL:
/api/questions/delete/{question_id}/ - 方法: DELETE
- 请求头:
Authorization: Bearer {token} - 响应: 204 No Content
3.3 考试管理
- 创建考试
-
URL:
/api/exams/create/ -
方法: POST
-
请求头:
Authorization: Bearer {token} -
请求体:
{"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120 } -
响应:
{"exam_id": 1,"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120,"created_at": "创建时间" }
- 获取所有考试
-
URL:
/api/exams/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
[{"exam_id": 1,"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120,"created_at": "创建时间"} ]
- 获取特定考试
-
URL:
/api/exams/get/{exam_id}/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
{"exam_id": 1,"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120,"created_at": "创建时间" }
- 更新考试
-
URL:
/api/exams/update/{exam_id}/ -
方法: PUT
-
请求头:
Authorization: Bearer {token} -
请求体:
{"exam_name": "新考试名称","start_time": "新开始时间","end_time": "新结束时间","duration": 150 } -
响应:
{"exam_id": 1,"exam_name": "新考试名称","start_time": "新开始时间","end_time": "新结束时间","duration": 150,"created_at": "创建时间" }
- 删除考试
- URL:
/api/exams/delete/{exam_id}/ - 方法: DELETE
- 请求头:
Authorization: Bearer {token} - 响应: 204 No Content
- 添加题目到考试
-
URL:
/api/exams/add_question/ -
方法: POST
-
请求头:
Authorization: Bearer {token} -
请求体:
{"exam": 1,"question": 1 } -
响应:
{"exam_question_id": 1,"exam": 1,"question": 1,"question_detail": {"question_id": 1,"content": "题目内容","question_type": "题目类型","difficulty_level": "难度级别","created_at": "创建时间"} }
- 获取考试的所有题目
-
URL:
/api/exams/questions/{exam_id}/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
[{"exam_question_id": 1,"exam": 1,"question": 1,"question_detail": {"question_id": 1,"content": "题目内容","question_type": "题目类型","difficulty_level": "难度级别","created_at": "创建时间"}} ]
- 自动组卷
-
URL:
/api/exams/generate_paper/ -
方法: POST
-
请求头:
Authorization: Bearer {token} -
请求体:
{"exam_id": 1,"easy_count": 5,"medium_count": 3,"hard_count": 2 } -
响应:
{"message": "成功添加 10 道题目到考试" }
3.4 成绩管理
- 添加成绩
-
URL:
/api/scores/add/ -
方法: POST
-
请求头:
Authorization: Bearer {token} -
请求体:
{"user": 1,"exam": 1,"score": 85 } -
响应:
{"score_id": 1,"user": 1,"exam": 1,"score": 85,"created_at": "创建时间","user_detail": {"user_id": 1,"username": "用户名","role": "角色","created_at": "创建时间"},"exam_detail": {"exam_id": 1,"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120,"created_at": "创建时间"} }
- 获取用户成绩
-
URL:
/api/scores/user/{user_id}/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
[{"score_id": 1,"user": 1,"exam": 1,"score": 85,"created_at": "创建时间","user_detail": {"user_id": 1,"username": "用户名","role": "角色","created_at": "创建时间"},"exam_detail": {"exam_id": 1,"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120,"created_at": "创建时间"}} ]
- 获取考试成绩
-
URL:
/api/scores/exam/{exam_id}/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
[{"score_id": 1,"user": 1,"exam": 1,"score": 85,"created_at": "创建时间","user_detail": {"user_id": 1,"username": "用户名","role": "角色","created_at": "创建时间"},"exam_detail": {"exam_id": 1,"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120,"created_at": "创建时间"}} ]
- 获取历史考试记录
-
URL:
/api/scores/history/{user_id}/ -
方法: GET
-
请求头:
Authorization: Bearer {token} -
响应:
[{"history_id": 1,"user": 1,"exam": 1,"score": 85,"completed_at": "完成时间","user_detail": {"user_id": 1,"username": "用户名","role": "角色","created_at": "创建时间"},"exam_detail": {"exam_id": 1,"exam_name": "考试名称","start_time": "开始时间","end_time": "结束时间","duration": 120,"created_at": "创建时间"}} ]

🦁 其它优质专栏推荐 🦁
🌟《Java核心系列(修炼内功,无上心法)》: 主要是JDK源码的核心讲解,几乎每篇文章都过万字,让你详细掌握每一个知识点!
🌟 《springBoot 源码剥析核心系列》:一些场景的Springboot源码剥析以及常用Springboot相关知识点解读
欢迎加入狮子的社区:『Lion-编程进阶之路』,日常收录优质好文
更多文章可持续关注上方🦁的博客,2025咱们顶峰相见!
