基于Django的驾校在线考试系统

基于Django设计一个驾校在线考试系统,包括前台考试系统和后台管理系统,前台考试系统包括考生登录、科目一和科目四自动组卷、调用摄像头拍照和成绩计算。后台管理系统包括学员管理、考试预约、成绩管理和题库管理。

一、后台管理系统

1.后台登录界面

        使用request.POST获取前端form表单提交的用户名查找user表,在获取用户名后再获取form表单提交的密码与用户密码进行比对,成功在session中录入用户信息,之后重定向至后台管理首页,否则提示登录失败的具体信息。

 try:
        #执行验证码校验
        if request.POST['code']!=request.session['verifycode']:
            context = {'info': '验证码错误!'}
            return render(request,'myadmin/index/login.html',context)
        #根据登录账号获取用户信息
        user = User.objects.get(username=request.POST['username'])
        md5 = hashlib.md5()
        s = request.POST['pass'] + user.password_salt  # 从表单中获取密码并添加干扰值
        md5.update(s.encode('utf-8'))  # 将要产生md5的子串放进去
        if user.password_hash==md5.hexdigest():  # 获取md5值
            #登录成功
            request.session['adminuser']=user.toDict()  #将当前登录成功的用户信息以adminuser为key写入到session中
            return redirect(reverse('myadmin_index'))  #重定向到后台管理首页
        else:
            context={'info':'登录密码错误!'}
    except Exception as err:
        print(err)
        context={"info":"登录账号不存在!"}
    return render(request,"myadmin/index/login.html",context)

2.学员管理

(1)添加学员

        表单通过POST提交给View中的insert()方法,该方法使用request.FILES.get()方获取照片,若没有则返回None,之后将图片保存到项目根目录的static/uploads/student路径下。之后创建一个Student对象,通过request.POST方法获取POST提交的数据,并将密码做md5处理,最后通过save()方法保存到数据库。

        # 照片的上传处理
        myfile = request.FILES.get('photo', None)
        print(myfile)
        if not myfile:
            return HttpResponse('没有照片上传文件信息')
        photo = str(time.time()) + '.' + myfile.name.split(',').pop()
        destination = open('./static/uploads/student/' + photo, 'wb+')
        for chunk in myfile.chunks():  # 分块写入文件
            destination.write(chunk)
        destination.close()
        ob=Student()
        ob.name=request.POST['name']
        ob.sex=request.POST['sex']
        ob.birthday=request.POST['birthday']
        ob.id_card=request.POST['id_card']
        ob.tel=request.POST['tel']
        ob.status_one=request.POST['one']
        ob.status_four=request.POST['four']
        ob.photo=photo

(2)删除学员

        点击删除按钮时,弹出确认删除提示框,点击确定后先通过request.GET.get()方法获取要删除的学员id,之后通过id获取学员的照片路径,然后通过os.remove()方法删除图片,最后使用delete()方法从数据库中删除对应的学员信息。

    try:
        bid = request.GET.get('oid', 0)
        ob=Student.objects.get(id=bid)
        photo_path='./static/uploads/student/' + ob.photo
        if os.path.exists(photo_path):
            os.remove(photo_path)
        ob.delete()  #从数据库中删除
        return HttpResponse('Y')
    except Exception as err:
        print(err)
        context = {'info': '删除失败!'}
        return HttpResponse('N')

(3)修改学员

         点击编辑按钮先获取学员id,之后跳转到对应学员的信息修改表单,点击提交后调用View中的update()方法,该方法先对图片进行判断,如果没有新图片上传,则保留原图片,如果上传了新的图片则会先删除原照片,再写入新照片,最后在使用request.POST方法获取其他数据并保存。

    try:
        # 获取原照片
        oldphoto = request.POST['oldphoto']
        # 图片的上传处理
        myfile = request.FILES.get("photo", None)
        if not myfile:
            photo = oldphoto
        else:
            photo = str(time.time()) + "." + myfile.name.split('.').pop()
            destination = open("./static/uploads/student/" + photo, "wb+")
            for chunk in myfile.chunks():  # 分块写入文件
                destination.write(chunk)
            destination.close()
            if ob.photo:
                # 删除原照片
                oldphoto_path = './static/uploads/student/' + ob.photo
                if os.path.exists(oldphoto_path):
                    os.remove(oldphoto_path)

(4)学员信息查找

        通过学号或姓名查找学员,搜索框为空时,读取Student表的所有数据显示在页面上,在搜索框中使用条件查找之后对数据进行条件过滤,将过滤后的信息显示在页面上。

    mywhere=[]#保存搜索条件
    pageIndex=[]
    #获取并判断搜索条件
    kw=request.GET.get('keyword',None)
    if kw:
        slist= slist.filter(Q(id__contains=kw) | Q(name__contains=kw))
        mywhere.append('keyword='+kw)

(5)查看学员详细信息

        点击学员姓名后,前端调用js的doShow()方法,该方法使用ajax将学员的学号提交给后台,再通过View中的detail()方法接收,根据学号查找对应的学员信息并显示在界面上。

function doShow(id){
            //$('#myModal').modal({keyboard:false})
            $.ajax({
                type:'get',
                url:"{% url 'myadmin_student_detail' %}",
                dataType:'text',
                data:{sid:id},
                async: false,
                success:function(res){
                    $("#myModal div.modal-body").empty().append(res);
                    $('#myModal').modal({keyboard:false})
                },
            });
        }
def detail(request):
    #加载学员信息详情
    sid = request.GET.get("sid", 0)
    print(sid)
    # 加载预约详情
    slist = Student.objects.get(id=sid)
    # 放置模板变量,加载模板并输出
    context = {'slist': slist}
    return render(request, "myadmin/student/detail.html", context)

3.考试预约

(1)添加预约

        点击考试预约后,跳转到预约界面,该界面可以选择考试科目和考试日期,每日限制50个预约名额,没有名额则无法预约。

$.ajax({
          url:'{% url 'myadmin_bookexam_surplus' %}',
          type:"post",
          data:{book_time:time,
                book_subject:subject},
          dataType:"JSON",
          success:function(count){
			$("#count").html("当日已预约人数:"+count.count);
			$("#sur").html("当日剩余人数:"+(50-count.count));
			if(50-count.count<=0){
			$("#stop").html("当日预约人数已达上限");
			document.getElementById("submit").style.backgroundColor  = '#555555';
			document.getElementById("submit").disabled=true;}
			else{
			document.getElementById("submit").style.backgroundColor  = '#399BFF';
			document.getElementById("submit").disabled=false;}
			}
          })

(2)查看预约详情

(3)修改预约

 

def update(request,uid=0):
    """执行修改"""
    try:
        ob=BookExam.objects.get(id=uid)
        ob.subject = request.POST['subject']
        ob.book_time = request.POST['book_time']
        ob.save()
        context = {'info': '修改成功!'}
    except Exception as err:
        context = {'info': '修改失败!'}
        print(err)
    return render(request,'myadmin/info.html',context)

4.成绩管理

        每个学员在完成考试后都会将考试成绩保存到数据库中,在成绩管理模块中可以显示所有学员的考试成绩,并且可以查看学员的成绩单详情。

        管理员只能对学员的成绩进行查看和删除操作,点击查看成绩单按钮后跳转到对应的成绩单页面,成绩单内容包括考生姓名、身份证号、考试时间、考试科目、考试成绩和考试结果。

5.题库管理

(1)添加试题

        点击添加试题跳转至添加页面,其中题目图片选择图片链接的方式添加,在题目类型和正确答案的下拉框中设计二级联动,当题目类型为单选或多选题时开放ABCD四个选项的输入框,题目为判断题时清空并禁用CD选项的输入框,正确答案中也只保留AB选项。

//二级联动部分代码
        if(first.selectedIndex == 2)
        {
            optionC.value="";
            optionD.value="";
            second.options.add(new Option("A", "1"));
            second.options.add(new Option("B", "2"));
            optionC.readOnly=true;
            optionD.readOnly=true;
            optionC.required=false;
            optionD.required=false;
        }

(2)修改试题

 

二、前台考试系统

1.登录界面

2.前台考试系统首页

        登录成功时,系统会先获取考生最新的预约信息,并将其存入session,如果考生没有预约或预约时间与当前时间不符,则无法开始考试。

         考生第一次交卷后,session中保存的考试次数信息增加一次,若第一次考试未通过,考生有第二次机会进行补考,若补考也没有通过,则无法再继续考试。

      <h3>小车理论考试 科目一</h3>
      <p>驾照类型: C1、C2  考试时间: 45分钟  题目数量: 100</p>
        {% if request.session.student.booktime1 == request.session.student.today %}
        {% if request.session.student.count1 < 2 %}
        <a href="{% url 'web_startexam_one' 1 %}" target="_self" class="center">
          {% else %}
        <a href="javascript:void(0);" onclick="count();" target="_self" class="center">
           {% endif %}
       开始考试
       <em><img src="{% static '/public/images/exam/img2_5.png' %}"></em>
     </a>
        {% else %}
      <a href="javascript:void(0);" onclick="book()" target="_self" class="center">
       开始考试
       <em><img src="{% static '/public/images/exam/img2_5.png' %}"></em>
     </a>
        {% endif %}

3.考试界面

        考试信息核对无误后,考生即可开始考试,考试界面包括学员信息,题目信息,题目提示和答题信息。如果考生是首次登陆考试,则会先生成试卷,以科目一为例,后台会先从数据库的题库表中随机选取60道选择和40道判断题。

        在考试过程中,如果考生因异常情况退出,重新登陆后会根据session获取之前的题目和作答信息,考生可以继续作答。

    if request.method == 'GET':
        omod = QuestionOne.objects
        clist = omod.filter(qtype=1).all()  # 单选
        tflist = omod.filter(qtype=2).all()  # 判断
        choice_list = random.sample(list(clist), 60)  # 选择60道选择题
        judge_list = random.sample(list(tflist), 40)  # 选择40道判断题
        question_list = choice_list + judge_list  # 所有试题
        request.session['student']['now1'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") #获得考试时间
        data3 = []  # 题目缓存

(1)调用摄像头

        摄像头的调用和拍照功能主要依靠JavaScript中的takePhotos()方法实现,该方法用到了 Video + Canvas + getUserMedia,在视频开启时主要是获取摄像头的视频流并显示在video标签中。

			var canvas = document.getElementById("canvas"),
			context = canvas.getContext("2d"),
			video = document.getElementById("video");
			function successCallback(stream) {
				// Set the source of the video element with the stream from the camera
				if (video.mozSrcObject !== undefined) {
					video.mozSrcObject = stream;
				} else {
					video.srcObject = stream;
				}
				video.play();
			}
            if (navigator.getUserMedia) {
				navigator.getUserMedia({video: true}, successCallback, errorCallback);
			} else {
				alert('浏览器不支持getUserMedia.');
				// Display a friendly "sorry" message to the user
			}

(2)拍照

        使用拍照功能时用到了Html Dom中的setInterval()方法,该方法可以按照指定的周期来调用函数,本系统指定5分钟拍照一次。在拍照函数中,先获取浏览器页面的canvas对象,再将获取的内容使用toDateURL()转换成base64编码,由于该编码以”data:image/png;base64,”开头,因此要写入文件还需进行剪切,这里使用substr()方法去除开头字符,获取一串base64数据,之后将该数据以ajax的方式提交给后台的getphoto()方法,该方法使用base64模块的b64decode()函数进行解码,将解码后的数据写入/static/getphoto路径下。

            //每隔5分钟自动拍照
			setInterval(function () { //每5分钟执行一次
				context.drawImage(video, 0, 0, 320, 320);
				//获取浏览器页面的画布对象
				var canvans = document.getElementById("canvas");
				//以下开始编 数据
				var imgData = canvans.toDataURL();
				//将图像转换为base64数据
				var base64Data = imgData.substr(22);
				//将获得的base64数据设置为photo的背景图
				document.getElementById("photo").src='data:image/png;base64,'+base64Data;
				$.ajax({
			        url:'{% url 'web_getphoto1' %}',
			        type:"post",
                    data:{img_str1:base64Data},
					dataType:"JSON"
					})}, 
					300000);
        img_data = base64.b64decode(img_str)
        today=time.strftime('%Y-%m-%d',time.localtime(time.time()))+' '
        strtime=str(time.time())[:10]
        name=request.session['student']['name']+' 科目一 '
        with open('./static/getphoto/'+name+today+strtime+'.jpg', 'wb+') as f:
            f.write(img_data)
            f.close()
        return HttpResponse(img_str)

(3)判断题

(4)多选题

(5)成绩计算

        考生完成作答后点击交卷,后台接收作答数组,将其与答案数组进行比对,如果相等,则正确数目+1。正确数计算完成后,将本次考试信息保存到数据库,若本次成绩大于90分,则将对应学员该科目的考试情况变更为通过。

    for i in range(100):
        op = 0
        if answer[i] == 'A':
            op = 1
        elif answer[i] == 'B':
            op = 2
        elif answer[i] == 'C':
            op = 3
        elif answer[i] == 'D':
            op = 4
        else:
            op = 0
        if int(r_answer[i]) == op:
            right_num += 1
            ob = Grade()
            ob.subject='科目一'
            ob.grade=r['right_num']
            ob.examtime=request.session['examtime']
            ob.sid_id=request.session['student']['id']
            ob.save()
            if right_num>=90:
                so = Student.objects.get(id=request.session['student']['id'])
                so.status_one=1
                so.update_at=datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                so.save()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值