时间:2023-10-02 03:00:02 | 来源:网站运营
时间:2023-10-02 03:00:02 来源:网站运营
[Python+Django] Web在线考试管理系统设计及代码实现: 本文最终实现一个Web在线考试管理系统,可作为Python Web,Django的练手项目,也可以作为计算机毕业设计参考项目。文末附源码链接
django-admin startproject DjangoExam
pip install pymysql
安装好之后, 进入DjangoExam 项目下的DjangoExam 文件夹,打开setting.py 文件,找到DATABASES配置项,修改DATABSES配置项为如下内容:DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 数据库引擎 'NAME': 'djangoexam', # 数据库名称 'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1 'PORT': 3306, # 端口 'USER': 'root', # 数据库用户名 'PASSWORD': '123456', # 数据库密码 }}
import pymysql pymysql.install_as_MySQLdb()
python manage.py startapp exam
注册APPINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'exam', #添加此项]
定义模型from django.db import models # 学院表class Academy(models.Model): id = models.AutoField('序号',primary_key=True) name = models.CharField('学院',max_length=20) # 修改显示的表的名字 class Meta: verbose_name = '学院' verbose_name_plural = '学院' def __str__(self): return self.name # 专业表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 Meta: verbose_name = '专业' verbose_name_plural = '专业' def __str__(self): return self.major # 课程表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 Meta: verbose_name = '课程' verbose_name_plural = '课程' def __str__(self): return self.course_name # 学生表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 Meta: verbose_name = '学生' verbose_name_plural = '学生信息表' def __str__(self): return self.sid # 题库表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 Meta: # 选择这个表之后显示的名字 verbose_name = '题库' # 显示的表名 verbose_name_plural = '题库' def __str__(self): return '<%s:%s>' % (self.course, self.title) # 试卷表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 Meta: # 选择这个表之后显示的名字 verbose_name = '试卷' verbose_name_plural = '试卷' # # 学生成绩表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) class Meta: verbose_name = '学生成绩' verbose_name_plural = '学生成绩' def __str__(self): return '<%s:%s>' % (self.sid,self.grade)
python manage.py makemigrations
最后通过命令创建app模型对应的数据库表:python manage.py migrate
定义视图函数登录:输入用户和密码,根据校验结果进行登录处理。这些需求都靠视图(View)来完成。
考试:展示考试试题及选项,根据选择的结果记录考试成绩。
# 学生登录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请求数据")
index:# 首页def index(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, 'index.html',{'student': student,'paper': paper}) else: return render(request, 'index.html')
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 stulogout(request): # logout(request) request.session.clear() url = reverse('exam:index') return redirect(url)
# 考试信息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) context = { 'student': student, 'paper': paper, 'title': title, 'subject':subject1, 'count': paper.count() # 数据表中数据的条数 } return render(request, 'exam.html', context=context)
def examinfo(request): if request.session.get('is_login',None): #若session认证为真 username = request.session.get('username',None) student = models.Student.objects.get(sid=username) # 查询成绩信息 grade = models.Record.objects.filter(sid=student.sid) return render(request, 'examinfo.html',{'student': student,'grade': grade}) else: return render(request, 'examinfo.html')
# 计算考试成绩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)
配置访问路由URLfrom django.contrib import adminfrom django.urls import path, includefrom django.conf.urls import urlfrom exam import views 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'), # 考试信息]
通过配置如上URL,Django 将会根据用户请求的 URL 来选择使用哪个视图。由于 popper.js 版本兼容问题,本系统采用 cdn 远程引入的形式。附上官网下载链接(进入下载页面,复制粘贴代码到新文件即可):
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), # 添加此项]
模板创建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', ], }, },]
接着我们在模板文件中新建三个文件:<!-- 载入静态文件-->{% load static %}<!-- 网站主语言 --><html lang="zh-cn"><head> <!-- 网站采用的字符编码 --> <meta charset="utf-8"> <!-- 预留网站标题的位置 --> <title>{% block title %}{% endblock %}</title> <!-- 引入bootstrap的css文件 --> <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.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>
<!-- 定义导航栏 --><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>
templates/footer.html:{% 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-white">Copyright © DjangoExam 2021</p> </div></footer>
上述三个文件是网站页面的通用组件模块,基本上每个页面都不会变,所以我们把他们独立出来。<!-- 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 }}&title={{ paper1.title }}&subject={{ paper1.course }}" class="card-link">开始考试</a> </div> </div> </div> {% endfor %} </div> </div> <p></p> </div></div>{% endblock content %}
login.html{% extends "base.html" %} {% load static %}{% block title %} 登录 {% endblock title %}{% block content %}<div class="container"> <div class="row justify-content-md-center"> <div class="col-4"> <br> <form method="post" action="/studentLogin/"><!-- {% csrf_token %}--> <!-- 账号 --> <div class="form-group"> <label >学生学号</label> <input type="text" class="form-control" name="sid" placeholder="输入学号"> </div> <!-- 密码 --> <div class="form-group"> <label for="password">密码</label> <input type="password" class="form-control" id="password" name="password" placeholder="输入密码"> </div> <!-- 提交按钮 --> <button type="submit" class="btn btn-primary">登录</button> <div class="form-group"> <br> <br> </div> </form> </div> </div></div>{% endblock content %}
exam.html<div class="container"> {% for paper1 in paper %} {% for test in paper1.pid.all %} <div class="row bg-light"> <div class="col-12"><!-- <div class="card">--><!-- <div class="card-body h-10">--> <div id="{{ forloop.counter }}"> <b>{{ forloop.counter}}.</b><span>({{ test.score }}分)</span> <b>{{ test.title }}</b> <ul> <li class="option"> <input type="radio" class="radioOrCheck" name="{{ test.id }}" value="A"/> <label>A. <p class="ue" style="display: inline;">{{ test.a }}</p> </label> </li> <li class="option"> <input type="radio" class="radioOrCheck" name="{{ test.id }}" value="B"/> <label> B.<p class="ue" style="display: inline;">{{ test.b }}</p> </label> </li> <li class="option"> <input type="radio" class="radioOrCheck" name="{{ test.id }}" value="C"/> <label> C.<p class="ue" style="display: inline;">{{ test.c}}</p> </label> </li> <li class="option"> <input type="radio" class="radioOrCheck" name="{{ test.id }}" value="D"/> <label> D.<p class="ue" style="display: inline;">{{ test.d }}</p> </label> </li> </ul><!-- </div>--><!-- </div>--> </div> </div> </div> {% endfor %} {% endfor %} </div>
examinfo.html<div class="container"> <div class="container"> <br> <h3>考试成绩</h3> <p></p> <table class="table"> <thead> <tr> <th>姓名</th> <th>科目</th> <th>成绩</th> <th>考试时间</th> </tr> </thead> <tbody> {% for grade1 in grade %} <tr class="table"> <td>{{ student.name }}</td> <td>{{ grade1.course }}</td> <td>{{ grade1.grade }}</td> <td>{{ grade1.rtime|date:"Y-m-d H:i:s"}}</td> </tr> {% endfor %} </tbody> </table> </div></div>
userfile.html<div class="container"> <br> <div class="row justify-content-md-center"> <div class="col-8"> <div class="panel panel-info"> <div class="panel-heading"> <h3 class="panel-title">个人信息</h3> </div> <div class="panel-body"> <table class="table table-borderless"> <tbody> <tr> <td>学号</td> <td>{{ student.sid }}</td> </tr> <tr class="table"> <td>姓名</td> <td>{{ student.name }}</td> </tr> <tr class="table"> <td>性别</td> {% if student.sex%} <td>男</td> {% else %} <td>女</td> {% endif %} </tr> <tr class="table"> <td>学院</td> <td>{{ student.academy }}</td> </tr> <tr class="table"> <td>专业</td> <td>{{ student.major }}</td> </tr> <tr class="table"> <td>邮箱地址</td> <td>{{ student.email }}</td> </tr> <tr class="table"> <td>出生日期</td> <td>{{ student.birth }}</td> </tr> </tbody> </table> </div> </div> </div> </div></div>
Django后台启用配置from django.contrib import adminfrom exam.models import Academy,Major, Course,Student,QuestionBank,TestPaper,Record# Register your models here. # 修改名称admin.site.site_header='在线考试系统后台'admin.site.site_title='在线考试系统' admin.site.register([Academy,Major,Course,Student,QuestionBank,TestPaper,Record])
运行服务器测试效果关键词:设计,实现,系统,管理,考试