本文介绍: 本文最终实现一个Web在线考试管理系统,可作为Python Web,Django的练手项目摘要系统实现学生在线考试管理基本功能,包括学生登录查看自己的个人信息考试信息;提供了在线考试界面后台管理员管理员添加学生管理学生管理成绩、添加课程添加题库题目和组建试卷等功能。本次的学生在线考试管理系统采用Python Django做后端、前端框架采用Bootstrap4实现实现学生考试动态管理,使得对信息管理更加及时、高效,提高了效率。同时还对系统开发原理功能特点和设计方案进行了介

本文最终实现一个Web在线考试管理系统,可作为Python Web,Django的练手项目

摘要

系统实现学生在线考试管理基本功能,包括学生登录查看自己的个人信息及考试信息;提供了在线考试的界面;后台管理员管理员添加学生、管理学生、管理成绩、添加课程添加题库题目和组建试卷等功能。本次的学生在线考试管理系统采用Python Django做后端、前端框架采用Bootstrap4实现,实现学生考试的动态管理,使得对信息的管理更加及时、高效,提高了效率。同时还对系统开发原理功能特点和设计方案进行了介绍
关键词:考试管理 openGauss数据库 Python Django Web

实验目的

实验通过学习开发基于数据库应用软件,达到:
(1)练习在应用程序使用操作数据库
(2)掌握数据库模式设计分析和实现的方法
(3)掌握数据库设计和实现的基本过程
(4)了解数据库应用软件开发的一般过程
(5)掌握openGauss数据库软件开发过程中的使用

报告正文

1. 概述

1.1课题题目:学生在线考试管理系统
1.2系统的主要目标
本系统的目标是实现在线考试管理系统所需的各种基本功能,包括学生登录查看相关信息导出学生信息等功能以及后台管理员添加学生、维护学生信息、成绩管理、管理考试相关信息等功能,还有公用的登录退出等功能
1.3 系统的开发环境运行环境
操作系统: Windows 10
数据库系统:openGauss数据库
开发工具: Pycharm社区版)
服务端: Python 3.8
Web框架: Django 3.2
前端框架: Bootstrap 4

2. 系统需求分析

学生在线考试系统主要满足来自三方面的需求,这三个方面分别是学生用户、教师用户管理员用户,也即是三类用户角色。
(1)学生用户是主要的需求者,主要需求功能是查看当前自己的考试信息、查看考试成绩并可导出以及进行在线考试等。
(2)教师用户主需求功能是为自己所教授的课程组建题库和相对应的试卷,并可以查看学生的考试信息等。
(3)管理员用户的功能需求较为复杂,包括对学生信息、教师信息、考试信息进行管理。
在线考试管理系统,主要包含如下几个功能模块

在这里插入图片描述

3. 系统总体设计及实现思路

系统设计包括三部分:数据库设计,功能函数视图设计,前端页面设计

3.1 数据库设计

根据对系统需求分析,得出该考试管理系统大致需要六个实体,他们的实体属性下图所示
在这里插入图片描述
根据所分析的各实体之间的联系可画完整的ER图如下所示
在这里插入图片描述
根据上面的实体联系图可以得出以下几个表:

3.2 页面及功能设计

为了实现我们前面功能模块我们设计如下几个功能页面
在这里插入图片描述
1、登录页面
其中需要登录,校验,登录后同时需要存储用户信息在Session中,以备登录后的页面使用
2、首页(考试信息页):
页面需要显示当前用户可以参考的考试试卷信息,在此页面点击开始考试可以跳转到考试页面
3、考试页面
展示对应试卷的题目选项信息,同时可以进行答题,交卷后可以自动计算考试分数并存入数据库
4、成绩显示页面
展示对应考试的考试结果
5、后台管理:
用于管理我们专业,考生,试卷,题库等基础信息,为了快速实现系统将直接启用Django自带的Admin管理功能。
6、个人详情:
用于展示个人详情信息。

4. 详细设计

学生在线考试系统是实现学生在线考试、查看相关信息的一个平台,整个学生在线考试系统共分为3个大模块:管理员模块,学生模块和公有模块,其中复杂方法模块的详细设计流程图如下。

4.1学生用户登录流程图

在这里插入图片描述

4.2 学生考试流程图

在这里插入图片描述

4.3自动判卷流程图

在这里插入图片描述

4.4学生查看信息流程图

在这里插入图片描述

4.5后台流程图

在这里插入图片描述

5. 软件实现和测试

5.1 openGauss数据连接

psycopg2连接数据
openGauss基于PostgreSQL9.2版本开发的,基本包括了PostgreSQL9.4的功能。所以可以采用连接postgresql方式连接openGauss数据库。
新建django项目下的setting中的DATABASES下进行以下配置

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres', #数据库名
        'USER': 'andy', #用户名
        'PASSWORD': 'test123', #密码
        'HOST': '192.168.56.101',#虚拟机ip
        'PORT': 26000 #openGauss数据口的端口
    }
}

项目文件夹打开终端执行python manage.py runserver
在这里插入图片描述
出现上面的界面没有报错即为连接openGauss数据库成功。

5.2 功能模块详细开发

一个Django项目框架搭建起来后,我们所有对系统的前后台所有的程序开发都可以在这个项目中进行了,一个典型的Django项目模块功能的开发包括如下几个步骤

# 学院表
class Academy(models.Model):
    id = models.AutoField('序号', primary_key=True)
    name = models.CharField('学院', max_length=20)
# 专业class Major(models.Model):
    id = models.AutoField('序号', primary_key=True)
    academy = models.ForeignKey(Academy, on_delete=models.CASCADE, verbose_name='学院')
    major = models.CharField('专业', max_length=30)

# 课程表
class Course(models.Model):
    id = models.AutoField('序号', primary_key=True)
    course_id = models.CharField('课程号', max_length=10)
    course_name = models.CharField('课程名称', max_length=30)

# 学生表
class Student(models.Model):
    sid = models.CharField('学号', max_length=12, primary_key=True)
    name = models.CharField('姓名', max_length=20, unique=True)
    sex = models.BooleanField('性别', choices=((0, '女'), (1, '男')))
    age = models.IntegerField('年龄')
    academy = models.ForeignKey(Academy, on_delete=models.CASCADE, verbose_name='学院')
    major = models.ForeignKey(Major, on_delete=models.CASCADE, verbose_name='专业')
    sclass = models.CharField('班级', max_length=20, help_text='例如: 17-03')
    email = models.EmailField('邮箱', default=None)  # 默认为空   唯一值
    pwd = models.CharField('密码', max_length=20)

# 题库class QuestionBank(models.Model):
    id = models.AutoField('序号', primary_key=True)
    major = models.ForeignKey(Major, on_delete=models.CASCADE, verbose_name='专业')
    course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='科目')
    title = models.TextField('题目')
    qtype = models.CharField('题目类型', choices=(('单选', '单选'), ('多选', '多选'), ('判断', '判断')), max_length=40)
    a = models.CharField('A选项', max_length=40)
    b = models.CharField('B选项', max_length=40)
    c = models.CharField('C选项', max_length=40)
    d = models.CharField('D选项', max_length=40)
    answer = models.CharField('答案', choices=(('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D')), max_length=4)
    difficulty = models.CharField('难度', choices=(('easy', '简单'), ('middle', '中等'), ('difficult', '难')), max_length=10)
    score = models.IntegerField('分值')
    
# 试卷表
class TestPaper(models.Model):
    id = models.AutoField('序号', primary_key=True)
    title = models.CharField('题目', max_length=40, unique=True)
    pid = models.ManyToManyField(QuestionBank)
    course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='科目')
    major = models.ForeignKey(Major, on_delete=models.CASCADE, verbose_name='考卷适合专业')
    time = models.IntegerField('考试时长', help_text='单位是分钟')
    examtime = models.DateTimeField('上次考试时间')
    
## 学生成绩表
class Record(models.Model):
    id = models.AutoField('序号', primary_key=True)
    sid = models.ForeignKey(Student, on_delete=models.CASCADE, verbose_name='学号', related_name='stu_xuehao')
    course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='考试科目', related_name='stu_course')
    grade = models.FloatField('成绩')
    rtime = models.DateTimeField('考试时间', blank=True, null=True)
    

在这里插入图片描述
定义视图函数
Django 中视图的概念是「一类具有相同功能和模板网页集合」。
比如,在一个考试系统中,我们可能需要如下几个视图:
登录:输入用户和密码,根据校验结果进行登录处理
考试:展示考试试题选项,根据选择结果记录考试成绩。
这些需求都靠视图(View)来完成。
每一个视图表现为一个简单的Python函数,它需要要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse对象,或者抛出一个异常比如 Http404。
视图函数中的request网页发来的请求有关,里面包含getpost内容、用户浏览器、系统等信息。
根据系统设计过程需要的功能,我们在exam/views.py文件中创建如下几个视图函数
在这里插入图片描述
在这里插入图片描述
下面以其中几个视图函数为例:

# 学生登录
def studentLogin(request):
    if request.method == 'POST':
        # 获取表单信息
        sid = request.POST.get('sid')
        password = request.POST.get('password')
        print("sid", sid, "password", password)
        # 通过学号获取该学生实体
        student = models.Student.objects.get(sid=sid)
        print(student)
        if password == student.pwd:  # 登录成功
            request.session['username']=sid    #user的值发送session里的username
            request.session['is_login']=True   #认证为真
            # 查询考试信息
            paper = models.TestPaper.objects.filter(major=student.major)
            # 查询成绩信息
            grade = models.Record.objects.filter(sid=student.sid)

            # 渲染index模板
            return render(request, 'index.html', {'student': student, 'paper': paper, 'grade': grade})
        else:
            return render(request, 'login.html', {'message': '密码正确'})
    elif request.method == 'GET':
        return render(request, 'login.html')
    else:
        return HttpResponse("请使用GET或POST请求数据")

def userfile(request):
    if request.session.get('is_login',None):  #若session认证为真
        username = request.session.get('username',None)
        print(username )
        student = models.Student.objects.get(sid=username)
        # 查询考试信息
        paper = models.TestPaper.objects.filter(major=student.major)
        return render(request, 'userfile.html',{'student': student})

def exportexaminfo(request):
    if not request.session.get('is_login', None):
        return HttpResponseRedirect('/studentLogin')

    username = request.session.get('username',None)
    # print(username)
    student = models.Student.objects.get(sid=username)
    grades = models.Record.objects.filter(sid=username)

    response = HttpResponse(content_type='text/csv')
    response['Content-Dispostion'] = 'attachment;filename="exam-info.csv"'

    writer = csv.writer(response)
    writer.writerow(['姓名', '科目', '成绩', '考试时间'])
    for grade in grades:
        writer.writerow([student.name, grade.course, grade.grade, grade.rtime])
    return response
def calculateGrade(request):
    if request.method == 'POST':
        sid = request.POST.get('sid')
        subject1 = request.POST.get('subject')
        student = models.Student.objects.get(sid=sid)
        paper = models.TestPaper.objects.filter(major=student.major)
        grade = models.Record.objects.filter(sid=student.sid)
        course = models.Course.objects.filter(course_name=subject1).first()
        now =  datetime.now()
        # 计算考试成绩
        questions = models.TestPaper.objects.filter(course__course_name=subject1).
            values('pid').values('pid__id','pid__answer','pid__score')

        stu_grade = 0  # 初始化一个成绩
        for p in questions:
            qid = str(p['pid__id'])
            stu_ans = request.POST.get(qid)
            cor_ans = p['pid__answer']
            if stu_ans == cor_ans:
                stu_grade += p['pid__score']
        models.Record.objects.create(sid_id=sid, course_id=course.id, grade=stu_grade,rtime=now)
        context = {
            'student': student,
            'paper': paper,
            'grade': grade
        }
        return render(request, 'index.html', context=context)

def calculateGrade(request):
    if request.method == 'POST':
        sid = request.POST.get('sid')
        subject1 = request.POST.get('subject')
        student = models.Student.objects.get(sid=sid)
        paper = models.TestPaper.objects.filter(major=student.major)
        grade = models.Record.objects.filter(sid=student.sid)
        course = models.Course.objects.filter(course_name=subject1).first()
        now =  datetime.now()
        # 计算考试成绩
        questions = models.TestPaper.objects.filter(course__course_name=subject1).
            values('pid').values('pid__id','pid__answer','pid__score')

        stu_grade = 0  # 初始化一个成绩
        for p in questions:
            qid = str(p['pid__id'])
            stu_ans = request.POST.get(qid)
            cor_ans = p['pid__answer']
            if stu_ans == cor_ans:
                stu_grade += p['pid__score']
        models.Record.objects.create(sid_id=sid, course_id=course.id, grade=stu_grade,rtime=now)
        context = {
            'student': student,
            'paper': paper,
            'grade': grade
        }
        return render(request, 'index.html', context=context)

# 考试信息
def startExam(request):
    sid = request.GET.get('sid')
    title = request.GET.get('title')  # 试卷名字 唯一
    subject1 = request.GET.get('subject')  # 考试科目
    # 获取学生信息
    student = models.Student.objects.get(sid=sid)
    # 试卷信息
    paper = models.TestPaper.objects.filter(title=title,course__course_name=subject1)
    count = (models.TestPaper.objects.filter(title=title).values('pid','time'))
    print(count)
    print(count[0]['time'])
    context = {
        'student': student,
        'paper': paper,
        'title': title,
        'subject':subject1,
        'count': len(count),   # 数据表数据条数
        'time': count[0]['time']
    }
    # print(context)
    return render(request, 'exam.html', context=context)

剩下具体的视图代码源码
配置访问路由URL
有了视图后,还需要将视图函数和Web网页链接对应起来。
url可以理解访问网站输入网址链接配置url后Django才知道怎样定位app。
打开DjangoExam/urls.py,输入如下代码

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^$',views.index),#默认访问首页
    url('index/',views.index,name='index'),
    url('studentLogin/',views.studentLogin,name='studentLogin'),#学生登录
    url('startExam/',views.startExam,name='startExam'),#开始考试
    url('calculateGrade/',views.calculateGrade,name='calculateGrade'),#考试评分
    path('stulogout/',views.stulogout,name='stulogout'), # 学生退出登录
    path('userfile/',views.userfile,name='userfile'), # 个人信息
    path('examinfo/',views.examinfo,name='examinfo'), # 考试信息
    path('exportexaminfo', views.exportexaminfo) # 导出考试成绩信息
]

静态资源准备配置
本系统前后端不分离,前端框架选用当前比较受欢迎的Bootstrap4,为了快速开发,本系统所有的页面都使用原生Bootstrap进行开发,未采用第三方模板主题
项目根目录新建一个文件夹static用于存放前端模板静态资源
下载的Bootstrap解压出来的cssjs两个文件复制static文件夹去。
把解压出来的jQuery文件夹复制到static文件夹去。
完成后Static文件结构下图
在这里插入图片描述

模板创建
在创建模板之前,我们先在根目录新建一个文件夹templates用于存放我们的所有的模板文件。
模板位置也同样需要进行配置指定模板的存放位置,在DjangoExam/settings.py 中进行如下配置:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

页面html采用模板继承的写法来简化页面代码编写,这样的也可以将页面中的功能高度相关的模块独立出来,有利于代码复用和后期功能的维护。具体页面代码结构下图所示
在这里插入图片描述
下面仅展示其中几个的具体代码
Header:

<!-- 定义导航栏 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
    <div class="container">
        <!-- 导航栏商标 -->
        <a class="navbar-brand" href="#">在线考试</a>
        <!-- 导航入口 -->
        <div>
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link" href="/index/">首页</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/examinfo/">考试记录</a>
                </li>
                <!-- Django的 if 模板语句 -->
                {% if request.session.username %}
                <!-- 如果用户已经登录,则显示用户名下拉框 -->
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        {{ request.session.username }}
                    </a>
                    <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                        <a class="dropdown-item" href="/userfile/">个人信息</a>
                        <a class="dropdown-item" href="/stulogout/">退出登录</a>
                    </div>
                </li>
                <!-- 如果用户未登录,则显示 “登录” -->
                {% else %}
                <li class="nav-item">
                    <a class="nav-link" href="/studentLogin/">登录</a>
                </li>
                <!-- if 语句这里结束 -->
                {% endif %}
                <li class="nav-item">
                    <a class="nav-link" href="/admin">管理员</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

Footer:

{% load static %}
<!-- Footer -->
<div>
    <br><br><br>
</div>
<footer class="py-3 bg-dark fixed-bottom">
    <div class="container">
        <p class="m-0 text-center text-muted">Copyright &amp;copy; DjangoExam 2021</p>
    </div>
</footer>
Base:
<!--    载入静态文件 引入static标签-->
{% load static %}
<!-- 网站语言 -->
<html lang="zh-cn">
<head>
    <!-- 网站采用的字符编码 -->
    <meta charset="utf-8">
    <!-- 预留网站标题的位置 -->
    <title>{% block title %}{% endblock %}</title>
    <!-- 引入bootstrapcss文件 -->
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
</head>
<body>
<!-- 引入导航栏 -->
{% include 'header.html' %}
<!-- 预留具体页面的位置 -->
{% block content %}{% endblock content %}
<!-- 引入注脚 -->
{% include 'footer.html' %}
<!-- bootstrap.js 依赖 jquery.js 和popper.js,因此在这里引入 -->
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="{% static 'jquery/jquery-3.6.0.min.js' %}"></script>
<!--
    popper.js 采用 cdn 远程引入,意思是你不需要把它下载本地。
    在实际的开发中推荐静态文件尽量都使用 cdn 的形式。
    教程采用本地引入是为了让读者了解静态文件本地部署流程。
-->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1-lts/dist/umd/popper.min.js"></script>

<!-- 引入bootstrap的js文件 -->
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
</body>

</html>

Index:

<!-- extends表明此页面继承自 base.html 文件 -->
{% extends "base.html" %}
{% load static %}
<!-- 写入 base.html 中定义的 title -->
{% block title %}
在线考试系统
{% endblock title %}
<!-- 写入 base.html 中定义的 content -->
{% block content %}
<div class="container">
    <div class="container">
        <br>
        <h3>考试信息</h3>
        <div class="container">
            <div class="row mt-4">
                {% for paper1 in paper %}
                <!-- 文章内容 -->
                <div class="col-6 mb-6">
                    <!-- 卡片容器 -->
                    <div class="card">
                        <!-- 标题 -->
                        <h4 class="card-header">{{ paper1.title }}</h4>
                        <!-- 摘要 -->
                        <div class="card-body">
                            <h4 class="card-title">{{ paper1.course }}</h4>
                            <p class="card-text">{{ paper1.examtime  }}</p>
                            <a href="/startExam/?sid={{ student.sid }}&amp;title={{ paper1.title }}&amp;subject={{ paper1.course }}"  class="card-link">开始考试</a>
                        </div>
                    </div>
                </div>
                {% endfor %}
            </div>
        </div>
        <p></p>
    </div>
</div>
{% endblock content %}

其他具体的html代码见源码所示

5.3 功能测试

学生在线考试考试管理系统模块功能测试如下所示
登录界面
在这里插入图片描述
登录成功后进入界面
在这里插入图片描述
学生选择开始考试:
在这里插入图片描述
考试时间到,自动交卷
在这里插入图片描述

查看考试成绩:
在这里插入图片描述
点击按钮导出考试成绩记录:在这里插入图片描述
在这里插入图片描述
查看学生信息:
在这里插入图片描述
后台管理登录界面
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
具体操作就不再一一截图了。

openGauss数据库中的内容如下所示

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验总结

1、通过这次数据库大作业的练习,进一步掌握数据库的方法技术提高软件开发的实际能力,培养工程设计能力和综合分析解决问题的能力。

  • 学习和实践了分析和设计软件系统的各种知识,包括面向对象的系统分析与设计,编码测试方面的知识。
  • 熟悉了如何根据实际需要分析实体关系,画出ER图从而设计出符合要求的数据库表。
  • 学习和实践的数据库的增删改查功能在具体功能开发中的使用。
  • 熟悉了openGauss数据库的相关操作
  • 学习了利用django框架进行web开发的流程。
    2、本系统基本实现了关键的功能模块,在功能上基本满足了预期的需求,但是由于时间较紧,有些模块的功能还不太完善,比如可以增加按科目导出成绩、增加教师管理模块、增加题目类型等。

实验代码

https://www.aliyundrive.com/s/RESTEu8osUK
提取码:k36p

原文地址:https://blog.csdn.net/weixin_45816954/article/details/124183612

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_12325.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注