時間:2023-10-02 03:00:02 | 來源:網(wǎng)站運營
時間:2023-10-02 03:00:02 來源:網(wǎng)站運營
[Python+Django] Web在線考試管理系統(tǒng)設(shè)計及代碼實現(xiàn): 本文最終實現(xiàn)一個Web在線考試管理系統(tǒng),可作為Python Web,Django的練手項目,也可以作為計算機畢業(yè)設(shè)計參考項目。文末附源碼鏈接
django-admin startproject DjangoExam
pip install pymysql
安裝好之后, 進入DjangoExam 項目下的DjangoExam 文件夾,打開setting.py 文件,找到DATABASES配置項,修改DATABSES配置項為如下內(nèi)容:DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 數(shù)據(jù)庫引擎 'NAME': 'djangoexam', # 數(shù)據(jù)庫名稱 'HOST': '127.0.0.1', # 數(shù)據(jù)庫地址,本機 ip 地址 127.0.0.1 'PORT': 3306, # 端口 'USER': 'root', # 數(shù)據(jù)庫用戶名 'PASSWORD': '123456', # 數(shù)據(jù)庫密碼 }}
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 # 學(xué)院表class Academy(models.Model): id = models.AutoField('序號',primary_key=True) name = models.CharField('學(xué)院',max_length=20) # 修改顯示的表的名字 class Meta: verbose_name = '學(xué)院' verbose_name_plural = '學(xué)院' def __str__(self): return self.name # 專業(yè)表class Major(models.Model): id = models.AutoField('序號',primary_key=True) academy = models.ForeignKey(Academy,on_delete=models.CASCADE,verbose_name='學(xué)院') major = models.CharField('專業(yè)',max_length=30) # 修改顯示的表的名字 class Meta: verbose_name = '專業(yè)' verbose_name_plural = '專業(yè)' 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 # 學(xué)生表class Student(models.Model): sid = models.CharField('學(xué)號',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='學(xué)院') major = models.ForeignKey(Major,on_delete=models.CASCADE,verbose_name='專業(yè)') 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 = '學(xué)生' verbose_name_plural = '學(xué)生信息表' 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='專業(yè)') 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='考卷適合專業(yè)') time = models.IntegerField('考試時長',help_text='單位是分鐘') examtime = models.DateTimeField('上次考試時間') class Meta: # 選擇這個表之后顯示的名字 verbose_name = '試卷' verbose_name_plural = '試卷' # # 學(xué)生成績表class Record(models.Model): id = models.AutoField('序號',primary_key=True) sid = models.ForeignKey(Student,on_delete=models.CASCADE,verbose_name='學(xué)號',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 = '學(xué)生成績' verbose_name_plural = '學(xué)生成績' def __str__(self): return '<%s:%s>' % (self.sid,self.grade)
python manage.py makemigrations
最后通過命令創(chuàng)建app模型對應(yīng)的數(shù)據(jù)庫表:python manage.py migrate
定義視圖函數(shù)登錄:輸入用戶和密碼,根據(jù)校驗結(jié)果進行登錄處理。這些需求都靠視圖(View)來完成。
考試:展示考試試題及選項,根據(jù)選擇的結(jié)果記錄考試成績。
# 學(xué)生登錄def studentLogin(request): if request.method == 'POST': # 獲取表單信息 sid = request.POST.get('sid') password = request.POST.get('password') print("sid", sid, "password", password) # 通過學(xué)號獲取該學(xué)生實體 student = models.Student.objects.get(sid=sid) print(student) if password == student.pwd: # 登錄成功 request.session['username']=sid #user的值發(fā)送給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請求數(shù)據(jù)")
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') # 考試科目 # 獲取學(xué)生信息 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() # 數(shù)據(jù)表中數(shù)據(jù)的條數(shù) } 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'),#學(xué)生登錄 url('startExam/',views.startExam,name='startExam'),#開始考試 url('calculateGrade/',views.calculateGrade,name='calculateGrade'),#考試評分 path('stulogout/',views.stulogout,name='stulogout'), # 學(xué)生退出登錄 path('userfile/',views.userfile,name='userfile'), # 個人信息 path('examinfo/',views.examinfo,name='examinfo'), # 考試信息]
通過配置如上URL,Django 將會根據(jù)用戶請求的 URL 來選擇使用哪個視圖。由于 popper.js 版本兼容問題,本系統(tǒng)采用 cdn 遠程引入的形式。附上官網(wǎng)下載鏈接(進入下載頁面,復(fù)制粘貼代碼到新文件即可):
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), # 添加此項]
模板創(chuàng)建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', ], }, },]
接著我們在模板文件中新建三個文件:<!-- 載入靜態(tài)文件-->{% load static %}<!-- 網(wǎng)站主語言 --><html lang="zh-cn"><head> <!-- 網(wǎng)站采用的字符編碼 --> <meta charset="utf-8"> <!-- 預(yù)留網(wǎng)站標題的位置 --> <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><!-- 引入導(dǎo)航欄 -->{% include 'header.html' %}<!-- 預(yù)留具體頁面的位置 -->{% 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 遠程引入,意思是你不需要把它下載到本地。 在實際的開發(fā)中推薦靜態(tài)文件盡量都使用 cdn 的形式。 教程采用本地引入是為了讓讀者了解靜態(tài)文件本地部署的流程。--><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>
<!-- 定義導(dǎo)航欄 --><nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <div class="container"> <!-- 導(dǎo)航欄商標 --> <a class="navbar-brand" href="#">在線考試</a> <!-- 導(dǎo)航入口 --> <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 %} <!-- 如果用戶已經(jīng)登錄,則顯示用戶名下拉框 --> <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 語句在這里結(jié)束 --> {% 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>
上述三個文件是網(wǎng)站頁面的通用組件模塊,基本上每個頁面都不會變,所以我們把他們獨立出來。<!-- extends表明此頁面繼承自 base.html 文件 -->{% extends "base.html" %}{% load static %}<!-- 寫入 base.html 中定義的 title -->{% block title %}在線考試系統(tǒng){% 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 %} <!-- 文章內(nèi)容 --> <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 >學(xué)生學(xué)號</label> <input type="text" class="form-control" name="sid" placeholder="輸入學(xué)號"> </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>學(xué)號</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>學(xué)院</td> <td>{{ student.academy }}</td> </tr> <tr class="table"> <td>專業(yè)</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='在線考試系統(tǒng)后臺'admin.site.site_title='在線考試系統(tǒng)' admin.site.register([Academy,Major,Course,Student,QuestionBank,TestPaper,Record])
運行服務(wù)器測試效果關(guān)鍵詞:設(shè)計,實現(xiàn),系統(tǒng),管理,考試
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。