基于Django实现的智慧校园考试系统-自动组卷算法实现

AI的出现,是否能替代IT从业者? 10w+人浏览 1.1k人参与

权限管理

项目定制业务:前端、后端(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 安装与运行

  1. 克隆项目:gitcodeGithup
  2. 安装依赖:pip install -r requirements.txt
  3. 配置数据库:修改settings.py中的数据库配置
  4. 运行服务器:python manage.py runserver

二.🦁 演示系统流程

2.1 管理员端

  1. 登录

1
2. 仪表板
在这里插入图片描述
3. 用户管理
在这里插入图片描述
4. 题库管理
在这里插入图片描述
在这里插入图片描述
5. 考试管理
在这里插入图片描述
6. 试卷管理

  • 手动组卷
    在这里插入图片描述
  • 自动组卷
    在这里插入图片描述
  1. 成绩管理
    在这里插入图片描述

2.2 学生端

  1. 首页
    在这里插入图片描述
  2. 考试列表
    在这里插入图片描述
  3. 查看成绩
    在这里插入图片描述
  4. 个人中心
    在这里插入图片描述
  5. 考试页面
    在这里插入图片描述

在这里插入图片描述

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_count
        if medium_count > 0:
            selected_questions.extend(random.sample(medium_questions, medium_count))
            total_questions += medium_count
        if 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).data
    exam_data['question_count'] = total_questions
    
    return Response({
        "message": f"成功自动生成试卷,包含 {total_questions} 道题目(每种题型:简单{easy_count}道,中等{medium_count}道,困难{hard_count}道)",
        "exam": exam_data
    }, status=status.HTTP_201_CREATED)

三.🦁 API接口文档

3.1 用户管理

  1. 注册用户
  • URL: /api/users/register/

  • 方法: POST

  • 请求体:

    {
      "username": "用户名",
      "password": "密码",
      "role": "admin或student"
    }
    
  • 响应:

    {
      "user_id": 1,
      "username": "用户名",
      "role": "admin或student",
      "created_at": "创建时间"
    }
    
  1. 用户登录
  • URL: /api/users/login/

  • 方法: POST

  • 请求体:

    {
      "username": "用户名",
      "password": "密码"
    }
    
  • 响应:

    {
      "token": "JWT令牌",
      "user": {
        "user_id": 1,
        "username": "用户名",
        "role": "admin或student"
      }
    }
    
  1. 获取当前用户信息
  • URL: /api/users/current/

  • 方法: GET

  • 请求头: Authorization: Bearer {token}

  • 响应:

    {
      "user_id": 1,
      "username": "用户名",
      "role": "admin或student",
      "created_at": "创建时间"
    }
    
  1. 获取所有用户
  • URL: /api/users/

  • 方法: GET

  • 请求头: Authorization: Bearer {token}

  • 响应:

    [
      {
        "user_id": 1,
        "username": "用户名",
        "role": "admin或student",
        "created_at": "创建时间"
      }
    ]
    
  1. 获取特定用户
  • URL: /api/users/{user_id}/

  • 方法: GET

  • 请求头: Authorization: Bearer {token}

  • 响应:

    {
      "user_id": 1,
      "username": "用户名",
      "role": "admin或student",
      "created_at": "创建时间"
    }
    
  1. 更新用户
  • URL: /api/users/{user_id}/update/

  • 方法: PUT

  • 请求头: Authorization: Bearer {token}

  • 请求体:

    {
      "username": "新用户名",
      "password": "新密码",
      "role": "新角色"
    }
    
  • 响应:

    {
      "user_id": 1,
      "username": "新用户名",
      "role": "新角色",
      "created_at": "创建时间"
    }
    
  1. 删除用户
  • URL: /api/users/{user_id}/delete/
  • 方法: DELETE
  • 请求头: Authorization: Bearer {token}
  • 响应: 204 No Content

3.2 题库管理

  1. 添加题目
  • 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": "创建时间"
    }
    
  1. 获取所有题目
  • 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": "创建时间"
      }
    ]
    
  1. 获取特定题目
  • 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": "创建时间"
    }
    
  1. 更新题目
  • 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": "创建时间"
    }
    
  1. 删除题目
  • URL: /api/questions/delete/{question_id}/
  • 方法: DELETE
  • 请求头: Authorization: Bearer {token}
  • 响应: 204 No Content

3.3 考试管理

  1. 创建考试
  • 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": "创建时间"
    }
    
  1. 获取所有考试
  • URL: /api/exams/

  • 方法: GET

  • 请求头: Authorization: Bearer {token}

  • 响应:

    [
      {
        "exam_id": 1,
        "exam_name": "考试名称",
        "start_time": "开始时间",
        "end_time": "结束时间",
        "duration": 120,
        "created_at": "创建时间"
      }
    ]
    
  1. 获取特定考试
  • URL: /api/exams/get/{exam_id}/

  • 方法: GET

  • 请求头: Authorization: Bearer {token}

  • 响应:

    {
      "exam_id": 1,
      "exam_name": "考试名称",
      "start_time": "开始时间",
      "end_time": "结束时间",
      "duration": 120,
      "created_at": "创建时间"
    }
    
  1. 更新考试
  • 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": "创建时间"
    }
    
  1. 删除考试
  • URL: /api/exams/delete/{exam_id}/
  • 方法: DELETE
  • 请求头: Authorization: Bearer {token}
  • 响应: 204 No Content
  1. 添加题目到考试
  • 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": "创建时间"
      }
    }
    
  1. 获取考试的所有题目
  • 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": "创建时间"
        }
      }
    ]
    
  1. 自动组卷
  • 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 成绩管理

  1. 添加成绩
  • 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": "创建时间"
      }
    }
    
  1. 获取用户成绩
  • 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": "创建时间"
        }
      }
    ]
    
  1. 获取考试成绩
  • 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": "创建时间"
        }
      }
    ]
    
  1. 获取历史考试记录
  • 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咱们顶峰相见!

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狮子也疯狂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值