main
parent
739784a75b
commit
97b34a0763
@ -0,0 +1,3 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.11" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.11 (pythonProject1)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
|
||||||
|
<component name="PyCharmProfessionalAdvertiser">
|
||||||
|
<option name="shown" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/DjangoExam.iml" filepath="$PROJECT_DIR$/.idea/DjangoExam.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,2 @@
|
|||||||
|
import pymysql
|
||||||
|
pymysql.install_as_MySQLdb()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
ASGI config for DjangoExam project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoExam.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
@ -0,0 +1,136 @@
|
|||||||
|
"""
|
||||||
|
Django settings for DjangoExam project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 3.2.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.2/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/3.2/ref/settings/
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = 'django-insecure-$z1j^bnfbn$epv=k&o@s#7)((t3=k%5^1=x+=^)rj1gcw43tjp'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'exam', #添加此项
|
||||||
|
]
|
||||||
|
|
||||||
|
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 = 'DjangoExam.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 = 'DjangoExam.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
|
||||||
|
'NAME': 'djangoexam', # 数据库名称
|
||||||
|
'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
|
||||||
|
'PORT': 3306, # 端口
|
||||||
|
'USER': 'root', # 数据库用户名
|
||||||
|
'PASSWORD': '12345678', # 数据库密码
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/3.2/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/3.2/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
STATICFILES_DIRS = [
|
||||||
|
os.path.join(BASE_DIR, 'static'), # 添加此项
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Default primary key field type
|
||||||
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
@ -0,0 +1,31 @@
|
|||||||
|
"""DjangoExam URL Configuration
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/3.2/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
from django.conf.urls import url
|
||||||
|
from 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'), # 考试信息
|
||||||
|
]
|
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for DjangoExam project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoExam.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,11 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
||||||
|
# 修改名称
|
||||||
|
admin.site.site_header='在线考试系统后台'
|
||||||
|
admin.site.site_title='在线考试系统'
|
||||||
|
|
||||||
|
from exam.models import Academy,Major, Course,Student,QuestionBank,TestPaper,Record
|
||||||
|
|
||||||
|
admin.site.register([Academy,Major,Course,Student,QuestionBank,TestPaper,Record])
|
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ExamConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'exam'
|
@ -0,0 +1,118 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-10-22 08:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Academy',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='序号')),
|
||||||
|
('name', models.CharField(max_length=20, verbose_name='学院')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '学院',
|
||||||
|
'verbose_name_plural': '学院',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Course',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='序号')),
|
||||||
|
('course_id', models.CharField(max_length=10, verbose_name='课程号')),
|
||||||
|
('course_name', models.CharField(max_length=30, verbose_name='课程名称')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '课程',
|
||||||
|
'verbose_name_plural': '课程',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Major',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='序号')),
|
||||||
|
('major', models.CharField(max_length=30, verbose_name='专业')),
|
||||||
|
('academy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.academy', verbose_name='学院')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '专业',
|
||||||
|
'verbose_name_plural': '专业',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='QuestionBank',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='序号')),
|
||||||
|
('title', models.TextField(verbose_name='题目')),
|
||||||
|
('qtype', models.CharField(choices=[('单选', '单选'), ('多选', '多选'), ('判断', '判断')], max_length=40, verbose_name='题目类型')),
|
||||||
|
('a', models.CharField(max_length=40, verbose_name='A选项')),
|
||||||
|
('b', models.CharField(max_length=40, verbose_name='B选项')),
|
||||||
|
('c', models.CharField(max_length=40, verbose_name='C选项')),
|
||||||
|
('d', models.CharField(max_length=40, verbose_name='D选项')),
|
||||||
|
('answer', models.CharField(choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D')], max_length=4, verbose_name='答案')),
|
||||||
|
('difficulty', models.CharField(choices=[('easy', '简单'), ('middle', '中等'), ('difficult', '难')], max_length=10, verbose_name='难度')),
|
||||||
|
('score', models.IntegerField(verbose_name='分值')),
|
||||||
|
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.course', verbose_name='科目')),
|
||||||
|
('major', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.major', verbose_name='专业')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '题库',
|
||||||
|
'verbose_name_plural': '题库',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TestPaper',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='序号')),
|
||||||
|
('title', models.CharField(max_length=40, unique=True, verbose_name='题目')),
|
||||||
|
('time', models.IntegerField(help_text='单位是分钟', verbose_name='考试时长')),
|
||||||
|
('examtime', models.DateTimeField(verbose_name='上次考试时间')),
|
||||||
|
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.course', verbose_name='科目')),
|
||||||
|
('major', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.major', verbose_name='考卷适合专业')),
|
||||||
|
('pid', models.ManyToManyField(to='exam.QuestionBank')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '试卷',
|
||||||
|
'verbose_name_plural': '试卷',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Student',
|
||||||
|
fields=[
|
||||||
|
('sid', models.CharField(max_length=12, primary_key=True, serialize=False, verbose_name='学号')),
|
||||||
|
('name', models.CharField(max_length=20, unique=True, verbose_name='姓名')),
|
||||||
|
('sex', models.BooleanField(choices=[(0, '女'), (1, '男')], verbose_name='性别')),
|
||||||
|
('age', models.IntegerField(verbose_name='年龄')),
|
||||||
|
('sclass', models.CharField(help_text='例如: 17-03', max_length=20, verbose_name='班级')),
|
||||||
|
('email', models.EmailField(default=None, max_length=254, verbose_name='邮箱')),
|
||||||
|
('pwd', models.CharField(max_length=20, verbose_name='密码')),
|
||||||
|
('academy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.academy', verbose_name='学院')),
|
||||||
|
('major', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.major', verbose_name='专业')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '学生',
|
||||||
|
'verbose_name_plural': '学生信息表',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Record',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='序号')),
|
||||||
|
('grade', models.FloatField(verbose_name='成绩')),
|
||||||
|
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stu_course', to='exam.course', verbose_name='考试科目')),
|
||||||
|
('sid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stu_xuehao', to='exam.student', verbose_name='学号')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '学生成绩',
|
||||||
|
'verbose_name_plural': '学生成绩',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-10-26 02:09
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('exam', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='record',
|
||||||
|
name='rtime',
|
||||||
|
field=models.DateTimeField(blank=True, null=True, verbose_name='考试时间'),
|
||||||
|
),
|
||||||
|
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,114 @@
|
|||||||
|
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)
|
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
@ -0,0 +1,20 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'exam'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
# path('',views.index,name='index'),
|
||||||
|
# path('stulogout/',views.stulogout,name='stulogout'), # 学生退出登录
|
||||||
|
# path('userfile/',views.userfile,name='userfile'), # 个人信息
|
||||||
|
# path('examinfo/',views.examinfo,name='examinfo'), # 个人信息
|
||||||
|
# path('tealogout/',views.tealogout,name='tealogout'), # 学生退出登录
|
||||||
|
# path('emailsend/',views.email_send,name='emailsend'), # 发送验证码
|
||||||
|
# path('sendemail/',views.send_my_email,name='sendemail'), # 发送验证码
|
||||||
|
# path('studentLogin/',views.studentLogin,name='studentLogin'), # 学生登录
|
||||||
|
# path('teacherLogin/',views.teacherLogin,name='teacherLogin'), # 老师登录
|
||||||
|
# path('startExam/',views.startExam,name='startExam'), # 开始考试
|
||||||
|
# path('calculateGrade/',views.calculateGrade,name='calculateGrade'), # 交卷计算成绩
|
||||||
|
# path('showGrade/',views.showGrade,name='showGrade'), # 成绩统计
|
||||||
|
|
||||||
|
]
|
@ -0,0 +1,124 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.shortcuts import render, redirect
|
||||||
|
from django.urls import reverse
|
||||||
|
from exam import models
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
# 学生登录
|
||||||
|
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请求数据")
|
||||||
|
|
||||||
|
|
||||||
|
# 首页
|
||||||
|
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('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)
|
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/.env python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run administrative tasks."""
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoExam.settings')
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
except ImportError as exc:
|
||||||
|
raise ImportError(
|
||||||
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
|
"available on your PYTHONPATH environment variable? Did you "
|
||||||
|
"forget to activate a virtual environment?"
|
||||||
|
) from exc
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,331 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2018 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2018 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@-ms-viewport {
|
||||||
|
width: device-width;
|
||||||
|
}
|
||||||
|
|
||||||
|
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tabindex="-1"]:focus {
|
||||||
|
outline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr[title],
|
||||||
|
abbr[data-original-title] {
|
||||||
|
text-decoration: underline;
|
||||||
|
-webkit-text-decoration: underline dotted;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
cursor: help;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
address {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-style: normal;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
dl {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol ol,
|
||||||
|
ul ul,
|
||||||
|
ol ul,
|
||||||
|
ul ol {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
position: relative;
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #007bff;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: transparent;
|
||||||
|
-webkit-text-decoration-skip: objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #0056b3;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]):focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
overflow: auto;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: middle;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
color: #6c757d;
|
||||||
|
text-align: left;
|
||||||
|
caption-side: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus {
|
||||||
|
outline: 1px dotted;
|
||||||
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
optgroup,
|
||||||
|
textarea {
|
||||||
|
margin: 0;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
html [type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
padding: 0;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="date"],
|
||||||
|
input[type="time"],
|
||||||
|
input[type="datetime-local"],
|
||||||
|
input[type="month"] {
|
||||||
|
-webkit-appearance: listbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
outline-offset: -2px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-cancel-button,
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
font: inherit;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
output {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,8 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2018 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2018 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,118 @@
|
|||||||
|
<!-- 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="row">
|
||||||
|
<p class="col-12 mt-4 mb-4">
|
||||||
|
<a>当前科目:{{ subject }}</a>
|
||||||
|
<a>当前考试用户:{{ student.name }}</a>
|
||||||
|
考试时长:
|
||||||
|
<b class="alt-1"> 01:40 </b>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<form action="/calculateGrade/" method="post">
|
||||||
|
<input type="hidden" name="sid" value="{{ student.sid }}">
|
||||||
|
<input type="hidden" name="subject" value="{{ subject }}">
|
||||||
|
<div class="row">
|
||||||
|
<b class="bi bi-alarm" id="timer" style="color:red"></b>
|
||||||
|
<p> </p>
|
||||||
|
<font><input type="submit" name="tijiao" value="交卷"></font>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 mt-4 mb-4">
|
||||||
|
<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="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>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<!--nr end-->
|
||||||
|
<div class="foot"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SCRIPT type="text/javascript">
|
||||||
|
var maxtime = 1000; //一个小时,按秒计算,自己调整!
|
||||||
|
$(function () {
|
||||||
|
timer = setInterval("CountDown()", 1000);
|
||||||
|
})
|
||||||
|
function CountDown() {
|
||||||
|
if (maxtime >= 0) {
|
||||||
|
minutes = Math.floor(maxtime / 60);
|
||||||
|
seconds = Math.floor(maxtime % 60);
|
||||||
|
msg = "距离结束还有" + minutes + "分" + seconds + "秒";
|
||||||
|
{#document.all["timer"].innerHTML = msg;#}
|
||||||
|
document.getElementById('timer').innerHTML = msg;
|
||||||
|
{#if (maxtime == 5 * 60)alert("还剩5分钟");#}
|
||||||
|
--maxtime;
|
||||||
|
} else{
|
||||||
|
{#clearInterval(timer);#}
|
||||||
|
{#alert("时间到,结束!");#}
|
||||||
|
document.getElementsByClassName('tijiao').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</SCRIPT>
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
<!-- 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>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
|
|
@ -0,0 +1,10 @@
|
|||||||
|
{% 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 2023</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
@ -0,0 +1,42 @@
|
|||||||
|
<!-- 定义导航栏 -->
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
<!-- 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 %}
|
||||||
|
|
@ -0,0 +1,30 @@
|
|||||||
|
{% 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 %}
|
@ -0,0 +1,55 @@
|
|||||||
|
{% extends "base.html" %} {% load static %}
|
||||||
|
{% block title %} 用户信息 {% endblock title %}
|
||||||
|
{% block content %}
|
||||||
|
<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>
|
||||||
|
{% endblock content %}
|
Loading…
Reference in new issue