Django框架實(shí)現(xiàn)在線考試系統(tǒng)的示例代碼
1.Django的簡(jiǎn)介
Django是一個(gè)基于MVC構(gòu)造的框架。但是在Django中,控制器接受用戶輸入的部分由框架自行處理,所以 Django 里更關(guān)注的是模型(Model)、模板(Template)和視圖(Views),稱為 MTV模式。它們各自的職責(zé)如下:
層次 | 職責(zé) |
---|---|
模型(Model),即數(shù)據(jù)存取層 | 模型(Model),即數(shù)據(jù)存取層 |
模板(Template),即表現(xiàn)層 | 處理與表現(xiàn)相關(guān)的決定: 如何在頁(yè)面或其他類型文檔中進(jìn)行顯示。 |
視圖(View),即業(yè)務(wù)邏輯層 | 存取模型及調(diào)取恰當(dāng)模板的相關(guān)邏輯。模型與模板的橋梁。 |
Django里重要的概念有:
- 路由映射
- 視圖函數(shù)
- 模板渲染
- Django自帶的ORM操作(對(duì)象關(guān)系映射)
2.項(xiàng)目的設(shè)計(jì)思路
1.在線考試系統(tǒng)需求如下:
(1)系統(tǒng)登錄:驗(yàn)證登錄用戶的身份,根據(jù)用戶身份進(jìn)入不同的頁(yè)面。
(2)學(xué)生管理:供管理員使用,用于維護(hù)學(xué)生基本信息。
(3)老師管理:供管理員使用,用于維護(hù)教師的基本信息。
(4)試題管理:供教師管理,用于維護(hù)題庫(kù)。
(5)組卷:供教師使用,教師可以根據(jù)考試科目,從題庫(kù)中選擇一些符合條件的試題,形成一份試卷。為了方便教師組卷,應(yīng)提供方便的查詢功能,使教師能查詢不同要求的試題。
(6)在線考試:供學(xué)生使用,根據(jù)學(xué)生的班級(jí)和登錄時(shí)間顯示應(yīng)考科目的試卷內(nèi)容。試卷完成提交或考試時(shí)間到,不再允許學(xué)生修改試卷;實(shí)現(xiàn)自動(dòng)評(píng)閱,記錄學(xué)生的考試成績(jī),并將評(píng)閱結(jié)果提供給學(xué)生。
(7)成績(jī)統(tǒng)計(jì):供教師使用,按照科目、班級(jí)等統(tǒng)計(jì)學(xué)生的考試成績(jī)。
(8)成績(jī)查詢:供教師和學(xué)生使用,提供不同查詢方式,使教師和學(xué)生可以按需查詢考試成績(jī)。
2.設(shè)計(jì)思路
(1)確定角色
由需求分析看出,系統(tǒng)有三個(gè)基本角色,學(xué)生、教師、管理員。
- 管理員負(fù)責(zé)后臺(tái)信息的維護(hù)
- 系統(tǒng)要能實(shí)現(xiàn)自動(dòng)閱卷功能
(2)數(shù)據(jù)庫(kù)表的設(shè)計(jì)
因此,我們至少需要如下幾個(gè)表:
- 學(xué)生表 student
- 教師表 teacher
- 題庫(kù)表 question(為了方便,題庫(kù)中都為單項(xiàng)選擇題)
- 試卷表 paper
- 學(xué)生成績(jī)表 grade
設(shè)計(jì)完表,我們還需要確定表間的關(guān)系,是1對(duì)1(1:1),1對(duì)多(1:n),還是多對(duì)多(n:m),這很重要,因?yàn)楹竺嫖覀冊(cè)趍odels.py中創(chuàng)建表時(shí),需要指出表間關(guān)系。
顯然
- 學(xué)生表和成績(jī)表,1個(gè)學(xué)生可參加多門考試,會(huì)有多個(gè)成績(jī),學(xué)生表和成績(jī)表為1:n
- 教師表和試卷表,1個(gè)教師會(huì)發(fā)布多套試卷,但1套試卷只能由1位教師發(fā)布,教師表和試卷表為1:n
- 試卷表和題庫(kù)表,1套試卷里包含多道題,題庫(kù)里的每道題也可出現(xiàn)在多個(gè)試卷中,故試卷表和題庫(kù)表為n:m
表的詳細(xì)設(shè)計(jì)如下:(使用MindMaster繪制,有點(diǎn)丑,請(qǐng)忽略,重點(diǎn)寫下自己的思考和思路)
3.搭建你的開發(fā)環(huán)境
IDE使用PyCharm(profession版的)
python 3.7, Django 2.1.0
數(shù)據(jù)庫(kù)為關(guān)系數(shù)據(jù)庫(kù)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(請(qǐng)指定版本號(hào),最新的Django需要數(shù)據(jù)庫(kù)mysql5.6以上),你可以使用pip list來(lái)查看版本,使用 pip uninstall django 來(lái)卸載django模塊
安裝mysql數(shù)據(jù)庫(kù)驅(qū)動(dòng) pip install pymysql
配置好后建立項(xiàng)目
(1) 在PyCharm中建立Django項(xiàng)目
圖1 建立項(xiàng)目
此處沒有使用虛擬環(huán)境,你也可以選擇 “New environment using”選項(xiàng)來(lái)創(chuàng)建一個(gè)虛擬環(huán)境(可以避免多個(gè)項(xiàng)目使用不同模塊的版本時(shí)發(fā)生沖突)
(2)創(chuàng)建app
Tools->Run manage.py task
在控制臺(tái)輸入 startapp student,創(chuàng)建一個(gè)student app,
之后需要將student app配置在項(xiàng)目的settings.py中,由于我的前臺(tái)需要用到css、BootStrap、一些圖片等文件,所以我在項(xiàng)目下建立static文件夾,并將其路徑配置在settings.py文件中。整體目錄如下:
(3)settings.py文件的配置
配置settings.py文件配置如下,請(qǐng)看注釋
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數(shù)據(jù)庫(kù) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'exam',#使用數(shù)據(jù)庫(kù)的名稱 'USER':'root',#用戶名 'PASSWORD':'123456',#密碼 'HOST':'127.0.0.1',#地址 'PORT':'3306'#端口號(hào) } } # 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/ #修改語(yǔ)言為中文 LANGUAGE_CODE = 'zh-hans' #修改時(shí)區(qū)為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 配置你的數(shù)據(jù)庫(kù)參數(shù)
- MIDDLEWARE 注釋掉了 # 'django.middleware.csrf.CsrfViewMiddleware'這一行
- STATICFILES_DIRS 添加新建的static文件夾
(4)在__init___.py文件添加mysql的驅(qū)動(dòng)模塊
import pymysql pymysql.install_as_MySQLdb()
4.分模塊詳細(xì)設(shè)計(jì)
(1)建表
在student下的models.py中建表
from django.db import models # Create your models here. # 為性別,學(xué)院 指定備選字段 SEX=( ('男','男'), ('女','女'), ) DEPT=( ('計(jì)算機(jī)與通信學(xué)院','計(jì)算機(jī)與通信學(xué)院'), ('電氣與自動(dòng)化學(xué)院','電氣與自動(dòng)化學(xué)院'), ('外國(guó)語(yǔ)學(xué)院','外國(guó)語(yǔ)學(xué)院'), ('理學(xué)院','理學(xué)院'), ) class Student(models.Model): id=models.CharField('學(xué)號(hào)',max_length=20,primary_key=True) name=models.CharField('姓名',max_length=20) sex=models.CharField('性別',max_length=4,choices=SEX,default='男') dept=models.CharField('學(xué)院',max_length=20,choices=DEPT,default=None) major=models.CharField('專業(yè)',max_length=20,default=None) password=models.CharField('密碼',max_length=20,default='111') email=models.EmailField('郵箱',default=None) birth=models.DateField('出生日期') class Meta: db_table='student' verbose_name='學(xué)生' verbose_name_plural=verbose_name def __str__(self): return self.id; class Teacher(models.Model): id=models.CharField("教工號(hào)",max_length=20,primary_key=True) name=models.CharField('姓名',max_length=20) sex=models.CharField('性別',max_length=4,choices=SEX,default='男') dept=models.CharField('學(xué)院',max_length=20,choices=DEPT,default=None) email=models.EmailField('郵箱',default=None) password=models.CharField('密碼',max_length=20,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選項(xiàng)',max_length=30) optionB=models.CharField('B選項(xiàng)',max_length=30) optionC=models.CharField('C選項(xiàng)',max_length=30) optionD=models.CharField('D選項(xiàng)',max_length=30) answer=models.CharField('答案',max_length=10,choices=ANSWER) level=models.CharField('等級(jí)',max_length=10,choices=LEVEL) score=models.IntegerField('分?jǐn)?shù)',default=1) class Meta: db_table='question' verbose_name='單項(xiàng)選擇題庫(kù)' verbose_name_plural=verbose_name def __str__(self): return '<%s:%s>'%(self.subject,self.title); class Paper(models.Model): #題號(hào)pid 和題庫(kù)為多對(duì)多的關(guān)系 pid=models.ManyToManyField(Question)#多對(duì)多 tid=models.ForeignKey(Teacher,on_delete=models.CASCADE)#添加外鍵 subject=models.CharField('科目',max_length=20,default='') major=models.CharField('考卷適用專業(yè)',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('科目',max_length=20,default='') grade=models.IntegerField() def __str__(self): return '<%s:%s>'%(self.sid,self.grade); class Meta: db_table='grade' verbose_name='成績(jī)' verbose_name_plural=verbose_name
(2)將模型映射到mysql數(shù)據(jù)庫(kù)中,很簡(jiǎn)單,打開 Run manage.py Task,輸入遷移命令
先輸入makemigrate命令,作用是生成sql文件(create table student(id,sex,…) ),執(zhí)行后可在student-> migrations下看到執(zhí)行結(jié)果
再輸入migrate命令,執(zhí)行makemigrate生成的sql語(yǔ)句,表就建好了,你可以使用navicat或workBench等工具看到Django為我們建好的表
(2)創(chuàng)建管理員
繼續(xù)輸入createsuperuser命令創(chuàng)建管理員,以便登陸后臺(tái)
(3)創(chuàng)建模板
在templates中建立index.html模板,作為考試系統(tǒng)首頁(yè).(可去官網(wǎng)下載BootStrap、JQuery)
在頭文件里引入時(shí)注意順序,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>在線考試系統(tǒng)</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>在線考試系統(tǒng) 首頁(yè)</h3></a> </li> <li> <button data-target="#stuModal" data-toggle="modal" class="btn btn-primary">學(xué)生登陸</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" >個(gè)人信息</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" >成績(jī)查詢</a> </li> </ul> <!-- Tab panes --> <div class="tab-content"> <div id="home" class="container tab-pane active"><br> <h3>個(gè)人信息</h3> <table class="table"> <thead> <tr> <th>屬性</th> <th>信息</th> </tr> </thead> <tbody> <tr> <td>學(xué)號(hào)</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>學(xué)院</td> <td>{{ student.dept }}</td> </tr> <tr class="table-success"> <td>專業(yè)</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>學(xué)號(hào)</th> <th>姓名</th> <th>考試科目</th> <th>考試時(shí)間</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>考試成績(jī)</h3> <p></p> <table class="table"> <thead> <tr> <th>姓名</th> <th>科目</th> <th>成績(jī)</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> {#學(xué)生登錄的模態(tài)對(duì)話框#} <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">學(xué)生登陸</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">學(xué)生學(xué)號(hào)</label> <div class="col-sm-9"> <input type="text" class="form-control" name="id" placeholder="輸入學(xué)號(hào)"> </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> {#老師登錄的模態(tài)對(duì)話框#} <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">教師工號(hào)</label> <div class="col-sm-9"> <input type="text" class="form-control" name="id" placeholder="輸入學(xué)號(hào)"> </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使用{{ }}來(lái)使用后臺(tái)傳來(lái)的數(shù)據(jù)
(4)創(chuàng)建視圖函數(shù)
在student->views.py中創(chuàng)建進(jìn)入首頁(yè)的視圖函數(shù)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')
將視圖函數(shù)配置在路由中,打開項(xiàng)目的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), #默認(rèn)訪問(wèn)首頁(yè) url(r'^$',views.index), ]
r表示使用正則表達(dá)式解析url地址,^表示開始,$表示結(jié)束,views.index表示調(diào)用視圖函數(shù)index
(5)啟動(dòng)服務(wù)器(可以看到效果了)
兩種方式啟動(dòng)服務(wù)器:執(zhí)行runserver命令,或點(diǎn)擊綠色小圖標(biāo)
點(diǎn)擊網(wǎng)址,默認(rèn)8000端口,成功后如下圖
我們還需要定制自己的后臺(tái),在student->admin.py中注冊(cè)各模塊
from django.contrib import admin from .models import Student,Teacher,Paper,Question,Grade # Register your models here. # 修改名稱 admin.site.site_header='在線考試系統(tǒng)后臺(tái)' admin.site.site_title='在線考試系統(tǒng)' @admin.register(Student) class StudentAdmin(admin.ModelAdmin): list_display = ('id','name','sex','dept','major','password','email','birth')# 要顯示哪些信息 list_display_links = ('id','name')#點(diǎn)擊哪些信息可以進(jìn)入編輯頁(yè)面 search_fields = ['name','dept','major','birth'] #指定要搜索的字段,將會(huì)出現(xiàn)一個(gè)搜索框讓管理員搜索關(guān)鍵詞 list_filter =['name','dept','major','birth']#指定列表過(guò)濾器,右邊將會(huì)出現(xiàn)一個(gè)快捷的過(guò)濾選項(xiàng)
對(duì)其他4個(gè)model注冊(cè)后臺(tái)
@admin.register(Teacher) class TeacherAdmin(admin.ModelAdmin): list_display = ('id', 'name', 'sex', 'dept', 'password', 'email', 'birth') list_display_links = ('id', 'name') search_fields = ['name', 'dept', 'birth'] list_filter = ['name','dept'] @admin.register(Question) class QuestionAdmin(admin.ModelAdmin): list_display = ('id','subject','title','optionA','optionB','optionC','optionD','answer','level','score')
刷新,點(diǎn)擊首頁(yè)管理員超鏈接,進(jìn)入后臺(tái),使用前邊創(chuàng)建的superuser賬戶和密碼登陸
進(jìn)入后臺(tái)
使用后臺(tái)添加學(xué)生信息
(6)實(shí)現(xiàn)學(xué)生的登陸
這里需要用到Django內(nèi)置的ORM模塊,不在贅述,需要的同學(xué)看前邊網(wǎng)站入門。
在views.py中創(chuàng)建studentLogin函數(shù)
學(xué)生登陸的form表單將學(xué)生輸入的學(xué)號(hào)(id),密碼(password)通過(guò)post方式提交給服務(wù)器,所以視圖函數(shù)先接受表單參數(shù),判斷用戶名和密碼與數(shù)據(jù)庫(kù)是否一致,若一致,則登陸成功。
登陸成功后,我需要發(fā)送至少三條信息給index.html,
(1)該學(xué)生的基本信息
(2)該學(xué)生考試信息,可通過(guò)該學(xué)生的專業(yè)名稱在試卷表中查到有哪些要進(jìn)行的考試
(3)該學(xué)生的考試成績(jī)信息,可通過(guò)學(xué)生的學(xué)號(hào)在paper表中查詢
代碼如下:
def studentLogin(request): if request.method=='POST': # 獲取表單信息 stuId=request.POST.get('id') password=request.POST.get('password') print("id",stuId,"password",password) # 通過(guò)學(xué)號(hào)獲取該學(xué)生實(shí)體 student=models.Student.objects.get(id=stuId) print(student) if password==student.password: #登錄成功 #查詢考試信息 paper=models.Paper.objects.filter(major=student.major) #查詢成績(jī)信息 grade=models.Grade.objects.filter(sid=student.id) # 渲染index模板 return render(request,'index.html',{'student':student,'paper':paper,'grade':grade}) else:return render(request,'index.html',{'message':'密碼不正確'})
(7)模板的渲染(數(shù)據(jù)的顯示)
登陸成功后,發(fā)送三個(gè)字典數(shù)據(jù)給index,index模板使用{{ }}、for等模板語(yǔ)句渲染
<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>學(xué)號(hào)</th> <th>姓名</th> <th>考試科目</th> <th>考試時(shí)間</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>考試成績(jī)</h3> <p></p> <table class="table"> <thead> <tr> <th>姓名</th> <th>科目</th> <th>成績(jī)</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)教師登陸同上,學(xué)生在線考試和系統(tǒng)自動(dòng)閱卷怎么實(shí)現(xiàn)呢?我是這樣做的
學(xué)生登陸成功后,點(diǎn)擊"開始考試"按鈕,按鈕將兩個(gè)請(qǐng)求信息發(fā)送到服務(wù)器,自己的學(xué)號(hào)和試卷的科目。
startExam視圖函數(shù)接收到學(xué)號(hào)和試卷的科目,找到試卷信息發(fā)送給另一模板(exam.html)渲染
因此,建立繼續(xù)建立exam.html模板和startExam視圖函數(shù)
def startExam(request): sid = request.GET.get('sid') subject1=request.GET.get('subject') #得到學(xué)生信息 student=models.Student.objects.get(id=sid) #試卷信息 paper=models.Paper.objects.filter(subject=subject1) # print('學(xué)號(hào)',sid,'考試科目',subject1) return render(request,'exam.html',{'student':student,'paper':paper,'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>在線答題考試系統(tǒng)</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> <!--時(shí)間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>在線考試系統(tǒng)</h3></a> </li> <li class="nav-item active"> <a class="nav-link"><h3>當(dāng)前科目:{{ 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</b> </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>合計(jì)</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>
效果是這樣的:
自動(dòng)閱卷就簡(jiǎn)單了:
- 學(xué)生提交自己的作答給服務(wù)器(同時(shí)發(fā)送自己的學(xué)號(hào)和考試科目)
- 服務(wù)器根據(jù)考試科目找到該試卷,并逐個(gè)比較學(xué)生作答和答案是否一致,若一致,則得到該題的分?jǐn)?shù),并累加學(xué)生成績(jī)
- 將學(xué)生的學(xué)號(hào)、該科成績(jī)、科目名稱作為一條記錄插入到grade表中,返回首頁(yè)
這里有個(gè)細(xì)節(jié),試卷中會(huì)有很多選擇題,后臺(tái)一次會(huì)接收到多個(gè)提交答案,我是這樣處理的,讓每個(gè)單選題(有4個(gè)選項(xiàng),使用同一name)的name屬性和該題在題庫(kù)表中的id 保持一致,這樣在獲取到題號(hào)后可以得到該題的答案,以便判斷是否作答正確,詳見exam.html。
計(jì)算成績(jī)的calGrade()視圖函數(shù)如下:
def calGrade(request): if request.method=='POST': # 得到學(xué)號(hào)和科目 sid=request.POST.get('sid') subject1 = request.POST.get('subject') # 重新生成Student實(shí)例,Paper實(shí)例,Grade實(shí)例,名字和index中for的一致,可重復(fù)渲染 student= models.Student.objects.get(id=sid) paper = models.Paper.objects.filter(major=student.major) grade = models.Grade.objects.filter(sid=student.id) # 計(jì)算該門考試的學(xué)生成績(jī) question= models.Paper.objects.filter(subject=subject1).values("pid").values('pid__id','pid__answer','pid__score') mygrade=0#初始化一個(gè)成績(jī)?yōu)? for p in question: qId=str(p['pid__id'])#int 轉(zhuǎn) string,通過(guò)pid找到題號(hào) myans=request.POST.get(qId)#通過(guò) qid 得到學(xué)生關(guān)于該題的作答 # print(myans) okans=p['pid__answer']#得到正確答案 # print(okans) if myans==okans:#判斷學(xué)生作答與正確答案是否一致 mygrade+=p['pid__score']#若一致,得到該題的分?jǐn)?shù),累加mygrade變量 #向Grade表中插入數(shù)據(jù) models.Grade.objects.create(sid_id=sid,subject=subject1,grade=mygrade) # print(mygrade) # 重新渲染index.html模板 return render(request,'index.html',{'student':student,'paper':paper,'grade':grade})
(9)使用百度e-charts可視化數(shù)據(jù)
教師查看學(xué)生成績(jī),可以統(tǒng)計(jì)各個(gè)分?jǐn)?shù)段的人數(shù)
我的思路:
- 教師查看學(xué)生成績(jī),點(diǎn)擊查看成績(jī)按鈕后,發(fā)送該科科目名稱給后臺(tái)后臺(tái)
- 視圖函數(shù)接收科目名,從grade表計(jì)算該科目各個(gè)分?jǐn)?shù)段的人數(shù),發(fā)送給前臺(tái)模板渲染,并可視化
視圖函數(shù)如下:
#教師查看成績(jī) 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.總結(jié)
到此這篇關(guān)于Django框架實(shí)現(xiàn)在線考試系統(tǒng)的示例代碼的文章就介紹到這了,更多相關(guān)Django 在線考試系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python Django框架介紹之模板標(biāo)簽及模板的繼承
- pycharm中django框架連接mysql數(shù)據(jù)庫(kù)的方法
- Python項(xiàng)目實(shí)戰(zhàn)之使用Django框架實(shí)現(xiàn)支付寶付款功能
- Python django框架 web端視頻加密的實(shí)例詳解
- Python web框架(django,flask)實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)讀寫分離的示例
- Django框架安裝及項(xiàng)目創(chuàng)建過(guò)程解析
- 淺談django框架集成swagger以及自定義參數(shù)問(wèn)題
- 解決django框架model中外鍵不落實(shí)到數(shù)據(jù)庫(kù)問(wèn)題
- Django框架獲取form表單數(shù)據(jù)方式總結(jié)
- Django添加bootstrap框架時(shí)無(wú)法加載靜態(tài)文件的解決方式
- 教你用Python3+mysql8.0搭建Django框架
相關(guān)文章
Python在畫圖時(shí)使用特殊符號(hào)的方法總結(jié)
在制作圖表時(shí),如果遇到需要利用特殊符號(hào)進(jìn)行表示時(shí)該怎么辦呢?不用慌,這篇文章為大家總結(jié)了python畫圖中使用各種特殊符號(hào)的方式,需要的可以參考一下2022-04-04Tensorflow 2.4 搭建單層和多層 Bi-LSTM 模型
這篇文章主要為大家介紹了Tensorflow 2.4 搭建單層 Bi-LSTM 模型和多層 Bi-LSTM 模型的實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01深度學(xué)習(xí)入門之Pytorch 數(shù)據(jù)增強(qiáng)的實(shí)現(xiàn)
這篇文章主要介紹了深度學(xué)習(xí)入門之Pytorch 數(shù)據(jù)增強(qiáng)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02python入門字符串拼接\截取\轉(zhuǎn)數(shù)字理解學(xué)習(xí)
本篇內(nèi)容我們主要講有關(guān)Python字符串的用法,包括字符串的拼接、字符串怎么轉(zhuǎn)數(shù)字、字符串的格式化、字符串函數(shù)等內(nèi)容,有需要的朋友可以借鑒參考下2021-09-09PyQt5實(shí)現(xiàn)界面(頁(yè)面)跳轉(zhuǎn)的示例代碼
這篇文章主要介紹了PyQt5實(shí)現(xiàn)界面跳轉(zhuǎn)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04用python寫一個(gè)定時(shí)提醒程序的實(shí)現(xiàn)代碼
今天小編就為大家分享一篇用python寫一個(gè)定時(shí)提醒程序的實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07python3.6.3+opencv3.3.0實(shí)現(xiàn)動(dòng)態(tài)人臉捕獲
這篇文章主要為大家詳細(xì)介紹了python3.6.3+opencv3.3.0實(shí)現(xiàn)動(dòng)態(tài)人臉捕獲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Python?Celery動(dòng)態(tài)添加定時(shí)任務(wù)生產(chǎn)實(shí)踐指南
elery是一種異步任務(wù)隊(duì)列,如果還不熟悉這個(gè)開源軟件的請(qǐng)先看看官方文檔,快速入門,下面這篇文章主要給大家介紹了關(guān)于Python?Celery動(dòng)態(tài)添加定時(shí)任務(wù)生產(chǎn)實(shí)踐的相關(guān)資料,需要的朋友可以參考下2022-08-08