Django框架實現線上考試系統的示例程式碼
1.Django的簡介
Django是一個基於MVC構造的框架。但是在Django中,控制器接受使用者輸入的部分由框架自行處理,所以 Django 裡更關注的是模型(Model)、模板(Template)和檢視(Views),稱為 MTV模式。它們各自的職責如下:
層次 | 職責 |
---|---|
模型(Model),即資料存取層 | 模型(Model),即資料存取層 |
模板(Template),即表現層 | 處理與表現相關的決定: 如何在頁面或其他型別文件中進行顯示。 |
檢視(View),即業務邏輯層 | 存取模型及調取恰當模板的相關邏輯。模型與模板的橋樑。 |
Django裡重要的概念有:
- 路由對映
- 檢視函式
- 模板渲染
- Django自帶的ORM操作(物件關係對映)
2.專案的設計思路
1.線上考試系統需求如下:
(1)系統登入:驗證登入使用者的身份,根據使用者身份進入不同的頁面。
(2)學生管理:供管理員使用,用於維護學生基本資訊。
(3)老師管理:供管理員使用,用於維護教師的基本資訊。
(4)試題管理:供教師管理,用於維護題庫。
(5)組卷:供教師使用,教師可以根據考試科目,從題庫中選擇一些符合條件的試題,形成一份試卷。為了方便教師組卷,應提供方便的查詢功能,使教師能查詢不同要求的試題。
(7)成績統計:供教師使用,按照科目、班級等統計學生的考試成績。
(8)成績查詢:供教師和學生使用,提供不同查詢方式,使教師和學生可以按需查詢考試成績。
2.設計思路
(1)確定角色
由需求分析看出,系統有三個基本角色,學生、教師、管理員。
- 管理員負責後臺資訊的維護
- 系統要能實現自動閱卷功能
(2)資料庫表的設計
因此,我們至少需要如下幾個表:
- 學生表 student
- 教師表 teacher
- 題庫表 question(為了方便,題庫中都為單項選擇題)
- 試卷表 paper
- 學生成績表 grade
設計完表,我們還需要確定表間的關係,是1對1(1:1),1對多(1:n),還是多對多(n:m),這很重要,因為後面我們在models.py中建立表時,需要指出表間關係。
顯然
- 學生表和成績表,1個學生可參加多門考試,會有多個成績,學生表和成績表為1:n
- 教師表和試卷表,1個教師會發布多套試卷,但1套試卷只能由1位教師釋出,教師表和試卷表為1:n
- 試卷表和題庫表,1套試卷裡包含多道題,題庫裡的每道題也可出現在多個試卷中,故試卷表和題庫表為n:m
表的詳細設計如下:(使用MindMaster繪製,有點醜,請忽略,重點寫下自己的思考和思路)
3.搭建你的開發環境
IDE使用PyCharm(profession版的)
python 3.7,Django 2.1.0
資料庫為關係資料庫mysql 5.6
為了更快的下載python模組,需要切換映象源,我使用阿里雲的映象(還有很多映象源),方法如下:
在 C:\Users\XXX(你的賬戶) 下建立 pip資料夾,在pip下建立 pip.ini檔案,輸入以下程式碼:
[global] index-url = http://mirrors.aliyun.com/pypi/simple/ [install] trusted-host=mirrors.aliyun.com
安裝所需模組
Django的安裝: pip install django==2.1.0(請指定版本號,最新的Django需要資料庫mysql5.6以上),你可以使用pip list來檢視版本,使用 pip uninstall django 來解除安裝django模組
安裝mysql資料庫驅動 pip install pymysql
配置好後建立專案
(1) 在PyCharm中建立Django專案
圖1 建立專案
此處沒有使用虛擬環境,你也可以選擇 “New environment using”選項來建立一個虛擬環境(可以避免多個專案使用不同模組的版本時發生衝突)
(2)建立app
Tools->Run manage.py task
在控制檯輸入 startapp student,建立一個student app,
之後需要將student app配置在專案的settings.py中,由於我的前臺需要用到css、BootStrap、一些圖片等檔案,所以我在專案下建立static資料夾,並將其路徑配置在settings.py檔案中。整體目錄如下:
(3)settings.py檔案的配置
配置settings.py檔案配置如下,請看註釋
INSTALLED_APPS = [ 'django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','student',#將建立的app名稱加入Installed_APPs中 ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware',# 'django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',] ROOT_URLCONF = 'onlineExam.urls' 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',],},] WSGI_APPLICATION = 'onlineExam.wsgi.application' # Database # https://docs.djangoproject.com/en/2.1/ref/settings/#databases #配置mysql資料庫 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql','NAME': 'exam',#使用資料庫的名稱 'USER':'root',#使用者名稱 'PASSWORD':'123456',#密碼 'HOST':'127.0.0.1',#地址 'PORT':'3306'#埠號 } } # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',{ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',{ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',{ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',] # Internationalization # https://docs.djangoproject.com/en/2.1/topics/i18n/ #修改語言為中文 LANGUAGE_CODE = 'zh-hans' #修改時區為shanghai TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS,JavaScript,Images) # https://docs.djangoproject.com/en/2.1/howto/static-files/ #新增static資料夾 STATIC_URL = '/static/' STATICFILES_DIRS=[ os.path.join(BASE_DIR,'static'),]
需要注意的地方有:
- NSTALLED_APPS 添加了新建的student app
- DATABASES 配置你的資料庫引數
- MIDDLEWARE 註釋掉了 # 'django.middleware.csrf.CsrfViewMiddleware'這一行
- STATICFILES_DIRS 新增新建的static資料夾
(4)在__init___.py檔案新增mysql的驅動模組
import pymysql pymysql.install_as_MySQLdb()
4.分模組詳細設計
(1)建表
在student下的models.py中建表
from django.db import models # Create your models here. # 為性別,學院 指定備選欄位 SEX=( ('男','男'),('女','女'),) DEPT=( ('計算機與通訊學院','計算機與通訊學院'),('電氣與自動化學院','電氣與自動化學院'),('外國語學院','外國語學院'),('理學院','理學院'),) class Student(models.Model): id=models.CharField('學號',max_length=20,primary_key=True) name=models.CharField('姓名',max_length=20) sex=models.CharField('性別',max_length=4,choices=SEX,default='男') dept=models.CharField('學院',choices=DEPT,default=None) major=models.CharField('專業',default=None) password=models.CharField('密碼',default='111') email=models.EmailField('郵箱',default=None) birth=models.DateField('出生日期') class Meta: db_table='student' verbose_name='學生' verbose_name_plural=verbose_name def __str__(self): return self.id; class Teacher(models.Model): id=models.CharField("教工號",default=None) email=models.EmailField('郵箱',default='000000') birth=models.DateField('出生日期') class Meta: db_table='teacher' verbose_name='教師' verbose_name_plural=verbose_name def __str__(self): return self.name; class Question(models.Model): ANSWER=( ('A','A'),('B','B'),('C','C'),('D','D'),) LEVEL={ ('1','easy'),('2','general'),('3','difficult'),} id = models.AutoField(primary_key=True) subject = models.CharField('科目',max_length=20) title = models.TextField('題目') optionA=models.CharField('A選項',max_length=30) optionB=models.CharField('B選項',max_length=30) optionC=models.CharField('C選項',max_length=30) optionD=models.CharField('D選項',max_length=30) answer=models.CharField('答案',max_length=10,choices=ANSWER) level=models.CharField('等級',choices=LEVEL) score=models.IntegerField('分數',default=1) class Meta: db_table='question' verbose_name='單項選擇題庫' verbose_name_plural=verbose_name def __str__(self): return '<%s:%s>'%(self.subject,self.title); class Paper(models.Model): #題號pid 和題庫為多對多的關係 pid=models.ManyToManyField(Question)#多對多 tid=models.ForeignKey(Teacher,on_delete=models.CASCADE)#新增外來鍵 subject=models.CharField('科目',default='') major=models.CharField('考卷適用專業',max_length=20) examtime=models.DateTimeField() class Meta: db_table='paper' verbose_name='試卷' verbose_name_plural=verbose_name def __str__(self): return self.major; class Grade(models.Model): sid=models.ForeignKey(Student,on_delete=models.CASCADE,default='')#新增外來鍵 subject=models.CharField('科目',default='') grade=models.IntegerField() def __str__(self): return '<%s:%s>'%(self.sid,self.grade); class Meta: db_table='grade' verbose_name='成績' verbose_name_plural=verbose_name
(2)將模型對映到mysql資料庫中,很簡單,開啟 Run manage.py Task,輸入遷移命令
先輸入makemigrate命令,作用是生成sql檔案(create table student(id,sex,…) ),執行後可在student-> migrations下看到執行結果
再輸入migrate命令,執行makemigrate生成的sql語句,表就建好了,你可以使用navicat或workBench等工具看到Django為我們建好的表
(2)建立管理員
繼續輸入createsuperuser命令建立管理員,以便登陸後臺
(3)建立模板
在templates中建立index.html模板,作為考試系統首頁.(可去官網下載BootStrap、JQuery)
在標頭檔案裡引入時注意順序,jquery須在bootstrap.min.js之前引入
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <link href="../static/bootstrap-4.3.1-dist/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="stylesheet"> <!-- 必須在引入bootstarp.js之前引入 --> <script src="../static/jquery-3.3.1.min.js"></script> <script src="../static/bootstrap-4.3.1-dist/js/bootstrap.min.js"></script> <link href="../static/css/index.css" rel="external nofollow" rel="stylesheet"> <title>線上考試系統</title> </head> <body> <nav class="navbar navbar-expand-sm bg-light navbar-light "> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="/toIndex/" rel="external nofollow" ><h3>線上考試系統 首頁</h3></a> </li> <li> <button data-target="#stuModal" data-toggle="modal" class="btn btn-primary">學生登陸</button> </li> <li> <button data-target="#teaModal" data-toggle="modal" class="btn btn-primary">教師登陸</button> </li> <li class="nav-item"> <a class="nav-link" href="/admin" rel="external nofollow" >管理員</a> </li> <li style="position: fixed;right: 70px; font-size: 40px;color: #9fcdff">{{ student.name }}{{ message }}</li> <a href="/logout/" rel="external nofollow" ><li style="position: fixed;right: 20px; font-size: 20px;top:22px;color:#cc1313">退出</li></a> </ul> </nav> <div class="container"> <br> <!-- Nav pills --> <ul class="nav nav-pills" role="tablist"> <li class="nav-item"> <a class="nav-link active" data-toggle="pill" href="#home" rel="external nofollow" >個人資訊</a> </li> <li class="nav-item"> <a class="nav-link" data-toggle="pill" href="#menu1" rel="external nofollow" >考試資訊</a> </li> <li class="nav-item"> <a class="nav-link" data-toggle="pill" href="#menu2" rel="external nofollow" >成績查詢</a> </li> </ul> <!-- Tab panes --> <div class="tab-content"> <div id="home" class="container tab-pane active"><br> <h3>個人資訊</h3> <table class="table"> <thead> <tr> <th>屬性</th> <th>資訊</th> </tr> </thead> <tbody> <tr> <td>學號</td> <td>{{ student.id }}</td> </tr> <tr class="table-primary"> <td>姓名</td> <td>{{ student.name }}</td> </tr> <tr class="table-success"> <td>性別</td> <td>{{ student.sex }}</td> </tr> <tr class="table-danger"> <td>學院</td> <td>{{ student.dept }}</td> </tr> <tr class="table-success"> <td>專業</td> <td>{{ student.major }}</td> </tr> <tr class="table-warning"> <td>郵箱地址</td> <td>{{ student.email }}</td> </tr> <tr class="table-active"> <td>出生日期</td> <td>{{ student.birth }}</td> </tr> </tbody> </table> </div> <div id="menu1" class="container tab-pane fade"><br> <h3>考試資訊</h3> <p></p> <table class="table"> <thead> <tr> <th>學號</th> <th>姓名</th> <th>考試科目</th> <th>考試時間</th> <th>操作</th> </tr> </thead> <tbody> {# 遍歷字典 paper #} {% for paper1 in paper %} <tr class="table-info"> <td>{{ student.id }}</td> <td>{{ student.name }}</td> <td>{{ paper1.subject }}{{ paper2.subject }}</td> <td>{{ paper1.examtime }} {{ paper2.examtime }}</td> <td> <a href="/startExam/?sid={{ student.id }}&subject={{ paper1.subject }}" rel="external nofollow" rel="external nofollow" > <button class="btn btn-primary" id="toExam+{{ paper1.subject }}">開始考試</button> </a> </td> </tr> {% endfor %} </tbody> </table> </div> <div id="menu2" class="container tab-pane fade"><br> <h3>考試成績</h3> <p></p> <table class="table"> <thead> <tr> <th>姓名</th> <th>科目</th> <th>成績</th> </tr> </thead> <tbody> {% for grade1 in grade %} <tr class="table-primary"> <td>{{ student.name }}</td> <td>{{ grade1.subject }}</td> <td>{{ grade1.grade }}</td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> {#學生登入的模態對話方塊#} <div class="modal fade" tabindex="-1" role="dialog" id="stuModal"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> <h4 class="modal-title">學生登陸</h4> </div> <form class="form-horizontal" action="/studentLogin/" method="post"> <div class="modal-body"> <div class="form-group"> <label class="col-sm-3 control-label">學生學號</label> <div class="col-sm-9"> <input type="text" class="form-control" name="id" placeholder="輸入學號"> </div> </div> <div class="form-group"> <label for="addr" class="col-sm-3 control-label">密碼</label> <div class="col-sm-9"> <!-- <textarea id="addr" class="form-control" rows="3"></textarea> --> <input type="password" class="form-control" name="password" placeholder="輸入密碼"> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary">登陸</button> </div> </form> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div> {#老師登入的模態對話方塊#} <div class="modal fade" tabindex="-1" role="dialog" id="teaModal"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> <h4 class="modal-title">教師登陸</h4> </div> <form class="form-horizontal" action="/teacherLogin/" method="post"> <div class="modal-body"> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">教師工號</label> <div class="col-sm-9"> <input type="text" class="form-control" name="id" placeholder="輸入學號"> </div> </div> <div class="form-group"> <label for="addr" class="col-sm-3 control-label">密碼</label> <div class="col-sm-9"> <!-- <textarea id="addr" class="form-control" rows="3"></textarea> --> <input type="password" name="password" placeholder="輸入密碼" class="form-control"> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary">登陸</button> </div> </form> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div> </body> <script> $("#toExam+{{ paper1.subject }}").click(function () { }); </script> </html>
Django使用{{ }}來使用後臺傳來的資料
(4)建立檢視函式
在student->views.py中建立進入首頁的檢視函式index()
from django.shortcuts import render,redirect from student import models from django.http import HttpResponse from django.contrib.auth import logout # Create your views here. def index(request): return render(request,'index.html')
將檢視函式配置在路由中,開啟專案的urls.py檔案
from django.contrib import admin from django.urls import path from django.conf.urls import url from student import views urlpatterns = [ #管理員登陸 path('admin/',admin.site.urls),#預設訪問首頁 url(r'^$',views.index),]
r表示使用正則表示式解析url地址,^表示開始,$表示結束,views.index表示呼叫檢視函式index
(5)啟動伺服器(可以看到效果了)
兩種方式啟動伺服器:執行runserver命令,或點選綠色小圖示
點選網址,預設8000埠,成功後如下圖
我們還需要定製自己的後臺,在student->admin.py中註冊各模組
from django.contrib import admin from .models import Student,Teacher,Paper,Question,Grade # Register your models here. # 修改名稱 admin.site.site_header='線上考試系統後臺' admin.site.site_title='線上考試系統' @admin.register(Student) class StudentAdmin(admin.ModelAdmin): list_display = ('id','name','sex','dept','major','password','email','birth')# 要顯示哪些資訊 list_display_links = ('id','name')#點選哪些資訊可以進入編輯頁面 search_fields = ['name','birth'] #指定要搜尋的欄位,將會出現一個搜尋框讓管理員搜尋關鍵詞 list_filter =['name','birth']#指定列表過濾器,右邊將會出現一個快捷的過濾選項
對其他4個model註冊後臺
@admin.register(Teacher) class TeacherAdmin(admin.ModelAdmin): list_display = ('id','birth') list_display_links = ('id','name') search_fields = ['name','birth'] list_filter = ['name','dept'] @admin.register(Question) class QuestionAdmin(admin.ModelAdmin): list_display = ('id','subject','title','optionA','optionB','optionC','optionD','answer','level','score')
重新整理,點選首頁管理員超連結,進入後臺,使用前邊建立的superuser賬戶和密碼登陸
進入後臺
使用後臺新增學生資訊
(6)實現學生的登陸
這裡需要用到Django內建的ORM模組,不在贅述,需要的同學看前邊網站入門。
在views.py中建立studentLogin函式
學生登陸的form表單將學生輸入的學號(id),密碼(password)通過post方式提交給伺服器,所以檢視函式先接受表單引數,判斷使用者名稱和密碼與資料庫是否一致,若一致,則登陸成功。
登陸成功後,我需要傳送至少三條資訊給index.html,
(1)該學生的基本資訊
(2)該學生考試資訊,可通過該學生的專業名稱在試卷表中查到有哪些要進行的考試
(3)該學生的考試成績資訊,可通過學生的學號在paper表中查詢
程式碼如下:
def studentLogin(request): if request.method=='POST': # 獲取表單資訊 stuId=request.POST.get('id') password=request.POST.get('password') print("id",stuId,"password",password) # 通過學號獲取該學生實體 student=models.Student.objects.get(id=stuId) print(student) if password==student.password: #登入成功 #查詢考試資訊 paper=models.Paper.objects.filter(major=student.major) #查詢成績資訊 grade=models.Grade.objects.filter(sid=student.id) # 渲染index模板 return render(request,'index.html',{'student':student,'paper':paper,'grade':grade}) else:return render(request,{'message':'密碼不正確'})
(7)模板的渲染(資料的顯示)
登陸成功後,傳送三個字典資料給index,index模板使用{{ }}、for等模板語句渲染
<tr class="table-warning"> <td>郵箱地址</td> <td>{{ student.email }}</td> </tr> <tr class="table-active"> <td>出生日期</td> <td>{{ student.birth }}</td> </tr> </tbody> </table> </div> <div id="menu1" class="container tab-pane fade"><br> <h3>考試資訊</h3> <p></p> <table class="table"> <thead> <tr> <th>學號</th> <th>姓名</th> <th>考試科目</th> <th>考試時間</th> <th>操作</th> </tr> </thead> <tbody> {# 遍歷字典 paper #} {% for paper1 in paper %} <tr class="table-info"> <td>{{ student.id }}</td> <td>{{ student.name }}</td> <td>{{ paper1.subject }}{{ paper2.subject }}</td> <td>{{ paper1.examtime }} {{ paper2.examtime }}</td> <td> <a href="/startExam/?sid={{ student.id }}&subject={{ paper1.subject }}" rel="external nofollow" rel="external nofollow" > <button class="btn btn-primary" id="toExam+{{ paper1.subject }}">開始考試</button> </a> </td> </tr> {% endfor %} </tbody> </table> </div> <div id="menu2" class="container tab-pane fade"><br> <h3>考試成績</h3> <p></p> <table class="table"> <thead> <tr> <th>姓名</th> <th>科目</th> <th>成績</th> </tr> </thead> <tbody> {% for grade1 in grade %} <tr class="table-primary"> <td>{{ student.name }}</td> <td>{{ grade1.subject }}</td> <td>{{ grade1.grade }}</td> </tr> {% endfor %} </tbody> </table> </div> </div>
(8)教師登陸同上,學生線上考試和系統自動閱卷怎麼實現呢?我是這樣做的
學生登陸成功後,點選"開始考試"按鈕,按鈕將兩個請求資訊傳送到伺服器,自己的學號和試卷的科目。
startExam檢視函式接收到學號和試卷的科目,找到試卷資訊傳送給另一模板(exam.html)渲染
因此,建立繼續建立exam.html模板和startExam檢視函式
def startExam(request): sid = request.GET.get('sid') subject1=request.GET.get('subject') #得到學生資訊 student=models.Student.objects.get(id=sid) #試卷資訊 paper=models.Paper.objects.filter(subject=subject1) # print('學號',sid,'考試科目',subject1) return render(request,'exam.html','subject':subject1})
exam模板如下:
<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="content-type" content="text/html;charset=UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <title>線上答題考試系統</title> <link href="../static/bootstrap-4.3.1-dist/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="stylesheet"> <!-- 必須在引入bootstarp.js之前引入 --> <script src="../static/jquery-3.3.1.min.js"></script> <script src="../static/bootstrap-4.3.1-dist/js/bootstrap.min.js"></script> <script src="../static/js/jquery-1.11.3.min.js"></script> <script src="../static/js/jquery.countdown.js"></script> <!--時間js--> <link href="../static/css/main.css" rel="external nofollow" rel="stylesheet" type="text/css" /> <link href="../static/css/test.css" rel="external nofollow" rel="stylesheet" type="text/css" /> <style> .hasBeenAnswer { background: #5d9cec; color:#fff; } </style> </head> <body> <nav class="navbar navbar-expand-sm bg-light navbar-light "> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link"><h3>線上考試系統</h3></a> </li> <li class="nav-item active"> <a class="nav-link"><h3>當前科目:{{ subject }}</h3></a> </li> <li style="position: fixed;right: 70px; font-size: 30px;color: #9fcdff">{{ student.name }}</li> </ul> </nav> <div class="main"> <!--nr start--> <div class="test_main"> <div class="nr_left"> <div class="test"> <form action="/calGrade/" method="post"> <input type="hidden" name="sid" value="{{ student.id }}"> <input type="hidden" name="subject" value="{{ subject }}"> <div class="test_title"> <p class="test_time"> <i class="icon iconfont"></i><b class="alt-1">01:40 </p> <font><input type="submit" name="tijiao" value="交卷"></font> </div> <div class="test_content"> <div class="test_content_title"> <h2>單選題</h2> <p> <span>共</span><i class="content_lit">10</i><span>題,</span> <span>合計</span><i class="content_fs">10</i><span>分</span> </p> </div> </div> <div class="test_content_nr"> <ul> {% for paper1 in paper %} {% for test in paper1.pid.all %} <li id="{{ forloop.counter }}"> <div class="test_content_nr_tt"> <i>{{ forloop.counter}}</i><span>({{ test.score }}分)</span> <font>{{ test.title }}</font> </div> <div class="test_content_nr_main"> <ul> <li class="option"> <input type="radio" class="radioOrCheck" name="{{ test.id }}" value="A"/> <label>A. <p class="ue" style="display: inline;">{{ test.optionA }}</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.optionB }}</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.optionC }}</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.optionD }}</p> </label> </li> </ul> </div> </li> {% endfor %} {% endfor %} </ul> </div> </form> </div> </div> </div> <!--nr end--> <div class="foot"></div> </div> </body> </html>
效果是這樣的:
自動閱卷就簡單了:
- 學生提交自己的作答給伺服器(同時傳送自己的學號和考試科目)
- 伺服器根據考試科目找到該試卷,並逐個比較學生作答和答案是否一致,若一致,則得到該題的分數,並累加學生成績
- 將學生的學號、該科成績、科目名稱作為一條記錄插入到grade表中,返回首頁
這裡有個細節,試卷中會有很多選擇題,後臺一次會接收到多個提交答案,我是這樣處理的,讓每個單選題(有4個選項,使用同一name)的name屬性和該題在題庫表中的id 保持一致,這樣在獲取到題號後可以得到該題的答案,以便判斷是否作答正確,詳見exam.html。
計算成績的calGrade()檢視函式如下:
def calGrade(request): if request.method=='POST': # 得到學號和科目 sid=request.POST.get('sid') subject1 = request.POST.get('subject') # 重新生成Student例項,Paper例項,Grade例項,名字和index中for的一致,可重複渲染 student= models.Student.objects.get(id=sid) paper = models.Paper.objects.filter(major=student.major) grade = models.Grade.objects.filter(sid=student.id) # 計算該門考試的學生成績 question= models.Paper.objects.filter(subject=subject1).values("pid").values('pid__id','pid__answer','pid__score') mygrade=0#初始化一個成績為0 for p in question: qId=str(p['pid__id'])#int 轉 string,通過pid找到題號 myans=request.POST.get(qId)#通過 qid 得到學生關於該題的作答 # print(myans) okans=p['pid__answer']#得到正確答案 # print(okans) if myans==okans:#判斷學生作答與正確答案是否一致 mygrade+=p['pid__score']#若一致,得到該題的分數,累加mygrade變數 #向Grade表中插入資料 models.Grade.objects.create(sid_id=sid,subject=subject1,grade=mygrade) # print(mygrade) # 重新渲染index.html模板 return render(request,'grade':grade})
(9)使用百度e-charts視覺化資料
教師檢視學生成績,可以統計各個分數段的人數
我的思路:
- 教師檢視學生成績,點選檢視成績按鈕後,傳送該科科目名稱給後臺後臺
- 檢視函式接收科目名,從grade表計算該科目各個分數段的人數,傳送給前臺模板渲染,並可視化
檢視函式如下:
#教師檢視成績 def showGrade(request): subject1=request.GET.get('subject') grade=models.Grade.objects.filter(subject=subject1) data1 = models.Grade.objects.filter(subject=subject1,grade__lt=60).count() data2 = models.Grade.objects.filter(subject=subject1,grade__gte=60,grade__lt=70).count() data3 = models.Grade.objects.filter(subject=subject1,grade__gte=70,grade__lt=80).count() data4 = models.Grade.objects.filter(subject=subject1,grade__gte=80,grade__lt=90).count() data5 = models.Grade.objects.filter(subject=subject1,grade__gte=90).count() data = {'data1': data1,'data2': data2,'data3': data3,'data4': data4,'data5': data5} return render(request,'showGrade.html',{'grade':grade,'data':data,'subject':subject1})
5.總結
到此這篇關於Django框架實現線上考試系統的示例程式碼的文章就介紹到這了,更多相關Django 線上考試系統內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!