考试api基本完成
This commit is contained in:
parent
d45afb9861
commit
295d5f886d
|
@ -0,0 +1,9 @@
|
|||
from django_filters import rest_framework as filters
|
||||
from .models import ExamRecord
|
||||
class ExamRecordFilter(filters.FilterSet):
|
||||
start_date = filters.DateFilter(field_name="update_time", lookup_expr='gte')
|
||||
end_date = filters.DateFilter(field_name="update_time", lookup_expr='lte')
|
||||
|
||||
class Meta:
|
||||
model = ExamRecord
|
||||
fields = ['is_pass', 'type', 'start_date', 'end_date', 'is_submited']
|
|
@ -0,0 +1,153 @@
|
|||
# Generated by Django 3.0.5 on 2022-11-07 05:56
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.postgres.fields.jsonb
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('exam', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AnswerDetail',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('user_answer', django.contrib.postgres.fields.jsonb.JSONField(blank=True, null=True)),
|
||||
('score', models.FloatField(default=0, verbose_name='本题得分')),
|
||||
('is_right', models.BooleanField(default=False, verbose_name='是否正确')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '答题记录',
|
||||
'verbose_name_plural': '答题记录',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Exam',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('code', models.CharField(blank=True, max_length=100, null=True, unique=True, verbose_name='考试编号')),
|
||||
('name', models.CharField(max_length=100, verbose_name='名称')),
|
||||
('place', models.CharField(blank=True, max_length=100, null=True, verbose_name='考试地点')),
|
||||
('open_time', models.DateTimeField(blank=True, null=True, verbose_name='开启时间')),
|
||||
('close_time', models.DateTimeField(blank=True, null=True, verbose_name='关闭时间')),
|
||||
('proctor_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='监考人姓名')),
|
||||
('proctor_phone', models.CharField(blank=True, max_length=100, null=True, verbose_name='监考人联系方式')),
|
||||
('chance', models.IntegerField(default=3, verbose_name='考试机会')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='exam_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Paper',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('name', models.CharField(max_length=200, verbose_name='名称')),
|
||||
('limit', models.IntegerField(default=0, verbose_name='限时(分钟)')),
|
||||
('total_score', models.FloatField(default=0, verbose_name='满分')),
|
||||
('pass_score', models.FloatField(default=0, verbose_name='通过分数')),
|
||||
('danxuan_count', models.IntegerField(default=0, verbose_name='单选数量')),
|
||||
('danxuan_score', models.FloatField(default=2, verbose_name='单选分数')),
|
||||
('duoxuan_count', models.IntegerField(default=0, verbose_name='多选数量')),
|
||||
('duoxuan_score', models.FloatField(default=4, verbose_name='多选分数')),
|
||||
('panduan_count', models.IntegerField(default=0, verbose_name='判断数量')),
|
||||
('panduan_score', models.FloatField(default=2, verbose_name='判断分数')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='paper_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '押题卷',
|
||||
'verbose_name_plural': '押题卷',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PaperQuestion',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('total_score', models.FloatField(default=0, verbose_name='单题满分')),
|
||||
('sort', models.PositiveSmallIntegerField(default=1)),
|
||||
('paper', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.Paper', verbose_name='试卷')),
|
||||
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.Question', verbose_name='试题')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='paper',
|
||||
name='questions',
|
||||
field=models.ManyToManyField(through='exam.PaperQuestion', to='exam.Question'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='paper',
|
||||
name='update_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='paper_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ExamRecord',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('name', models.CharField(max_length=200, verbose_name='名称')),
|
||||
('type', models.CharField(choices=[('自助模考', '自助模考'), ('押卷模考', '押卷模考'), ('正式考试', '正式考试')], default='自助模考', max_length=50, verbose_name='考试类型')),
|
||||
('limit', models.IntegerField(default=0, verbose_name='限时(分钟)')),
|
||||
('total_score', models.FloatField(default=0, verbose_name='总分')),
|
||||
('score', models.FloatField(default=0, verbose_name='得分')),
|
||||
('took', models.IntegerField(default=0, verbose_name='耗时(秒)')),
|
||||
('start_time', models.DateTimeField(verbose_name='开始答题时间')),
|
||||
('end_time', models.DateTimeField(verbose_name='结束答题时间')),
|
||||
('is_pass', models.BooleanField(default=True, verbose_name='是否通过')),
|
||||
('questions', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, verbose_name='下发的题目列表')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='examrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('detail', models.ManyToManyField(through='exam.AnswerDetail', to='exam.Question', verbose_name='答题记录')),
|
||||
('exam', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='exam.Exam', verbose_name='关联的正式考试')),
|
||||
('paper', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='exam.Paper', verbose_name='所用试卷')),
|
||||
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='examrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '考试记录',
|
||||
'verbose_name_plural': '考试记录',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='exam',
|
||||
name='paper',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='exam.Paper', verbose_name='使用的试卷'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='exam',
|
||||
name='update_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='exam_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='answerdetail',
|
||||
name='examrecord',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.ExamRecord'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='answerdetail',
|
||||
name='question',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exam.Question'),
|
||||
),
|
||||
]
|
|
@ -112,7 +112,7 @@ class ExamRecord(CommonAModel):
|
|||
detail = models.ManyToManyField(Question, verbose_name='答题记录', through='AnswerDetail')
|
||||
is_pass = models.BooleanField(default=True, verbose_name='是否通过')
|
||||
exam = models.ForeignKey(Exam, verbose_name='关联的正式考试', null=True, blank=True, on_delete= models.SET_NULL)
|
||||
questions = JSONField(default=list, verbose_name='下发的题目列表', blank=True)
|
||||
is_submited = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '考试记录'
|
||||
|
@ -122,6 +122,7 @@ class ExamRecord(CommonAModel):
|
|||
|
||||
class AnswerDetail(BaseModel):
|
||||
examrecord = models.ForeignKey(ExamRecord, on_delete=models.CASCADE)
|
||||
total_score = models.FloatField(default=0, verbose_name='该题满分')
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE)
|
||||
user_answer = JSONField(null=True,blank=True)
|
||||
score = models.FloatField(default=0, verbose_name='本题得分')
|
||||
|
@ -129,4 +130,5 @@ class AnswerDetail(BaseModel):
|
|||
|
||||
class Meta:
|
||||
verbose_name = '答题记录'
|
||||
verbose_name_plural = verbose_name
|
||||
verbose_name_plural = verbose_name
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
from rest_framework.serializers import ModelSerializer, CharField, Serializer, SerializerMethodField, FloatField
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.exam.models import Question, Questioncat, Paper, Exam, PaperQuestion
|
||||
from apps.exam.models import Question, Questioncat, Paper, Exam, PaperQuestion, ExamRecord, AnswerDetail
|
||||
|
||||
|
||||
class QuestioncatSerializer(ModelSerializer):
|
||||
|
@ -22,54 +22,162 @@ class PaperSerializer(ModelSerializer):
|
|||
exclude = ('questions',)
|
||||
|
||||
|
||||
class QuestionReadSerializer(ModelSerializer):
|
||||
class PaperQuestionSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Question
|
||||
exclude = ['right']
|
||||
model = PaperQuestion
|
||||
fields = ['question', 'total_score', 'sort']
|
||||
|
||||
class PaperQuestionSerializer(Serializer):
|
||||
id = CharField(label='题目ID')
|
||||
total_score = FloatField(label='单题满分')
|
||||
|
||||
class PaperCreateUpdateSerializer(ModelSerializer):
|
||||
questions_ = PaperQuestionSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Paper
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class PaperQuestionDetailSerializer(ModelSerializer):
|
||||
id = serializers.IntegerField(source='question.id')
|
||||
name = serializers.ReadOnlyField(source='question.name')
|
||||
options = serializers.ReadOnlyField(source='question.options')
|
||||
right = serializers.ReadOnlyField(source='question.right')
|
||||
type = serializers.ReadOnlyField(source='question.type')
|
||||
img = serializers.ReadOnlyField(source='question.img')
|
||||
questioncat_name = serializers.ReadOnlyField(source='question.questioncat.name')
|
||||
questioncat_name = serializers.ReadOnlyField(
|
||||
source='question.questioncat.name')
|
||||
level = serializers.ReadOnlyField(source='question.level')
|
||||
|
||||
class Meta:
|
||||
model = PaperQuestion
|
||||
fields = ('id','name','options','right','type','level','total_score','questioncat_name', 'img')
|
||||
fields = ('id', 'name', 'options', 'right', 'type', 'level',
|
||||
'total_score', 'questioncat_name', 'img', 'question')
|
||||
|
||||
|
||||
class PaperQuestionShortSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = PaperQuestion
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class PaperDetailSerializer(ModelSerializer):
|
||||
questions_ = SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Paper
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
def get_questions_(self, instance):
|
||||
pqs = PaperQuestion.objects.filter(paper=instance)
|
||||
return PaperQuestionDetailSerializer(pqs, many=True).data
|
||||
|
||||
|
||||
class ExamCreateUpdateSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Exam
|
||||
fields = ['name', 'place', 'open_time', 'close_time', 'proctor_name', 'proctor_phone']
|
||||
fields = ['name', 'place', 'open_time',
|
||||
'close_time', 'proctor_name', 'proctor_phone']
|
||||
|
||||
|
||||
class ExamListSerializer(ModelSerializer):
|
||||
create_by_name = CharField(source='create_by.name', read_only=True)
|
||||
paper_ = PaperSerializer(source='paper', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Exam
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
|
||||
class ExamDetailSerializer(ModelSerializer):
|
||||
create_by_name = CharField(source='create_by.name', read_only=True)
|
||||
paper_ = PaperSerializer(source='paper', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Exam
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class ExamAttendSerializer(Serializer):
|
||||
code = CharField(label="考试编号")
|
||||
code = CharField(label="考试编号")
|
||||
|
||||
|
||||
class ExamRecordListSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
考试列表序列化
|
||||
"""
|
||||
took_format = serializers.SerializerMethodField()
|
||||
create_by_name = serializers.CharField(
|
||||
source='create_by.name', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ExamRecord
|
||||
exclude = ('detail',)
|
||||
|
||||
def get_took_format(self, obj):
|
||||
m, s = divmod(obj.took, 60)
|
||||
h, m = divmod(m, 60)
|
||||
return "%02d:%02d:%02d" % (h, m, s)
|
||||
|
||||
|
||||
class ExamRecordDetailSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
考试详情序列化
|
||||
"""
|
||||
took_format = serializers.SerializerMethodField()
|
||||
questions_ = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = ExamRecord
|
||||
exclude = ('detail',)
|
||||
|
||||
def get_took_format(self, obj):
|
||||
m, s = divmod(obj.took, 60)
|
||||
h, m = divmod(m, 60)
|
||||
return "%02d:%02d:%02d" % (h, m, s)
|
||||
|
||||
def get_questions(self, obj):
|
||||
objs = AnswerDetail.objects.select_related('question').filter(
|
||||
examrecord=obj).order_by('question__type')
|
||||
return AnswerDetailSerializer(instance=objs, many=True).data
|
||||
|
||||
|
||||
class AnswerDetailUpdateSerializer(serializers.Serializer):
|
||||
id = serializers.CharField(label='下发ID')
|
||||
user_answer = serializers.JSONField(label='作答')
|
||||
|
||||
|
||||
class ExamRecordSubmitSerializer(serializers.ModelSerializer):
|
||||
questions_ = AnswerDetailUpdateSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = ExamRecord
|
||||
fields = ['questions_']
|
||||
|
||||
|
||||
class AnswerDetailSerializer(ModelSerializer):
|
||||
name = serializers.ReadOnlyField(source='question.name')
|
||||
options = serializers.ReadOnlyField(source='question.options')
|
||||
right = serializers.ReadOnlyField(source='question.right')
|
||||
type = serializers.ReadOnlyField(source='question.type')
|
||||
img = serializers.ReadOnlyField(source='question.img')
|
||||
questioncat_name = serializers.ReadOnlyField(
|
||||
source='question.questioncat.name')
|
||||
level = serializers.ReadOnlyField(source='question.level')
|
||||
|
||||
class Meta:
|
||||
model = PaperQuestion
|
||||
fields = ['id', 'question', 'name', 'options', 'right', 'type', 'level',
|
||||
'total_score', 'questioncat_name', 'img', 'user_answer', 'score', 'is_right']
|
||||
|
||||
|
||||
class AnswerDetailOutSerializer(ModelSerializer):
|
||||
name = serializers.ReadOnlyField(source='question.name')
|
||||
options = serializers.ReadOnlyField(source='question.options')
|
||||
type = serializers.ReadOnlyField(source='question.type')
|
||||
img = serializers.ReadOnlyField(source='question.img')
|
||||
questioncat_name = serializers.ReadOnlyField(
|
||||
source='question.questioncat.name')
|
||||
level = serializers.ReadOnlyField(source='question.level')
|
||||
|
||||
class Meta:
|
||||
model = PaperQuestion
|
||||
fields = ['id', 'question', 'name', 'options', 'type', 'level',
|
||||
'total_score', 'questioncat_name', 'img', 'user_answer', 'score', 'is_right']
|
||||
|
|
|
@ -2,8 +2,8 @@ from django.shortcuts import render
|
|||
from rest_framework.viewsets import ModelViewSet
|
||||
from apps.exam.exports import export_question
|
||||
from apps.exam.models import Question, Questioncat, PaperQuestion
|
||||
from apps.exam.serializers import (QuestionSerializer, QuestioncatSerializer, PaperSerializer,
|
||||
ExamCreateUpdateSerializer, ExamListSerializer, ExamAttendSerializer, PaperDetailSerializer, PaperCreateUpdateSerializer)
|
||||
from apps.exam.serializers import (QuestionSerializer, QuestioncatSerializer, PaperSerializer, ExamDetailSerializer, ExamRecordDetailSerializer, ExamListSerializer,
|
||||
ExamCreateUpdateSerializer, ExamListSerializer, ExamRecordSubmitSerializer, PaperDetailSerializer, PaperCreateUpdateSerializer, AnswerDetailOutSerializer, ExamRecordListSerializer)
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
@ -13,6 +13,10 @@ from django.conf import settings
|
|||
from apps.exam.models import Paper, Exam, ExamRecord, AnswerDetail
|
||||
from django.utils import timezone
|
||||
from django.db import transaction
|
||||
from rest_framework.serializers import Serializer
|
||||
from datetime import datetime
|
||||
from apps.exam.filters import ExamRecordFilter
|
||||
from datetime import timedelta
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
@ -221,24 +225,37 @@ class PaperViewSet(ModelViewSet):
|
|||
paper = Paper.objects.create(**vdata)
|
||||
q_list = []
|
||||
for i in questions_:
|
||||
question = Question.objects.get(id=i['id'])
|
||||
q_list.append(PaperQuestion(question=question, total_score=i['total_score'], paper=paper))
|
||||
q_list.append(PaperQuestion(question=i['question'], total_score=i['total_score'], paper=paper))
|
||||
PaperQuestion.objects.bulk_create(q_list)
|
||||
return Response(status=201)
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
return super().update(request, *args, **kwargs)
|
||||
# 有考试在执行,不可更新
|
||||
paper = self.get_object()
|
||||
sr = PaperCreateUpdateSerializer(instance=paper, data=request.data)
|
||||
sr.is_valid(raise_exception=True)
|
||||
vdata = sr.validated_data
|
||||
questions_ = vdata.pop('questions_')
|
||||
Paper.objects.filter(id=paper.id).update(**vdata)
|
||||
q_list = []
|
||||
for i in questions_:
|
||||
q_list.append(PaperQuestion(question=i['question'], total_score=i['total_score'], paper=paper))
|
||||
PaperQuestion.objects.filter(paper=paper).delete()
|
||||
PaperQuestion.objects.bulk_create(q_list)
|
||||
return Response()
|
||||
|
||||
|
||||
class ExamViewSet(ModelViewSet):
|
||||
perms_map = {'*': '*'}
|
||||
queryset = Exam.objects.all()
|
||||
queryset = Exam.objects.all().select_related('paper', 'create_by')
|
||||
ordering = ['-id']
|
||||
search_fields = ('name',)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action in ['create', 'update']:
|
||||
return ExamCreateUpdateSerializer
|
||||
elif self.action in ['retrieve']:
|
||||
return ExamDetailSerializer
|
||||
return ExamListSerializer
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
|
@ -248,24 +265,116 @@ class ExamViewSet(ModelViewSet):
|
|||
instance.delete()
|
||||
return Response(status=204)
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map=[{'post': '*'}], serializer_class=ExamAttendSerializer)
|
||||
def attend(self, request, *args, **kwargs):
|
||||
@action(methods=['post'], detail=True, perms_map=[{'post': '*'}], serializer_class=Serializer, permission_classes = [IsAuthenticated])
|
||||
def start(self, request, *args, **kwargs):
|
||||
"""
|
||||
参加考试
|
||||
开始考试
|
||||
|
||||
参加考试
|
||||
开始考试返回时间和题目信息
|
||||
"""
|
||||
sr = ExamAttendSerializer(data=request.data)
|
||||
sr.is_valid(raise_exception=True)
|
||||
vdata = sr.validated_data
|
||||
code = vdata['code']
|
||||
exam = self.get_object()
|
||||
now = timezone.now()
|
||||
exam = Exam.objects.filter(
|
||||
code=code, open_time__lt=now, close_time__gt=now).first()
|
||||
if exam:
|
||||
tests = ExamRecord.objects.filter(
|
||||
if now < exam.open_time or now > exam.close_time:
|
||||
raise ParseError('不在考试时间范围')
|
||||
tests = ExamRecord.objects.filter(
|
||||
exam=exam, create_by=request.user)
|
||||
if tests.count() < exam.chance: # 还有考试机会就可以接着考
|
||||
return Response(ExamListSerializer(instance=exam).data)
|
||||
chance_used = tests.count()
|
||||
if chance_used > exam.chance:
|
||||
raise ParseError('考试机会已用完')
|
||||
raise ParseError('有效考试不存在')
|
||||
if exam.paper:
|
||||
er = ExamRecord()
|
||||
er.type = '正式考试'
|
||||
er.name = '正式考试' + now.strftime('%Y%m%d%H%M')
|
||||
er.limit = exam.paper.limit
|
||||
er.paper = exam.paper
|
||||
er.total_score = exam.paper.total_score
|
||||
er.start_time = now
|
||||
er.is_pass = False
|
||||
er.exam = exam
|
||||
er.save()
|
||||
ret = {}
|
||||
ret['examrecord'] = er.id
|
||||
pqs = PaperQuestion.objects.filter(paper=exam.paper).order_by('id')
|
||||
details = []
|
||||
for i in pqs:
|
||||
details.append(AnswerDetail(examrecord=er, question=i.question, total_score=i.total_score))
|
||||
AnswerDetail.objects.bulk_create(details)
|
||||
ads = AnswerDetail.objects.select_related('question').filter(examrecord=er).order_by('id')
|
||||
ret['questions_'] = AnswerDetailOutSerializer(instance=ads, many=True).data
|
||||
return Response(ret)
|
||||
raise ParseError('暂不支持')
|
||||
|
||||
|
||||
class ExamRecordViewSet(ModelViewSet):
|
||||
"""
|
||||
考试记录列表和详情
|
||||
"""
|
||||
perms_map = {'get': '*', 'post': '*', 'delete':'examrecord_delete'}
|
||||
queryset = ExamRecord.objects.select_related('create_by')
|
||||
serializer_class = ExamRecordListSerializer
|
||||
ordering_fields = ['create_time', 'score', 'took', 'update_time']
|
||||
ordering = ['-update_time']
|
||||
search_fields = ('create_by__name', 'create_by__username')
|
||||
filterset_class = ExamRecordFilter
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'retrieve':
|
||||
return ExamRecordDetailSerializer
|
||||
return ExamRecordListSerializer
|
||||
|
||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def self(self, request, pk=None):
|
||||
'''
|
||||
个人考试记录
|
||||
'''
|
||||
queryset = ExamRecord.objects.filter(create_by=request.user).order_by('-update_time')
|
||||
page = self.paginate_queryset(queryset)
|
||||
serializer = self.get_serializer(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map=[{'post': '*'}], serializer_class=Serializer, permission_classes = [IsAuthenticated])
|
||||
def submit(self, request, pk=None):
|
||||
'''
|
||||
提交答卷
|
||||
|
||||
提交答卷
|
||||
'''
|
||||
er = self.get_object()
|
||||
now = timezone.now()
|
||||
if er.create_by != request.user:
|
||||
raise ParseError('提交人有误')
|
||||
exam = er.exam
|
||||
if not exam:
|
||||
raise ParseError('暂不支持')
|
||||
if now > exam.close_time + timedelta(minutes=30):
|
||||
raise ParseError('考试时间已过, 提交失败')
|
||||
serializer = ExamRecordSubmitSerializer(data = request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data
|
||||
questions_ = vdata['questions_']
|
||||
# 后端判卷
|
||||
ads = AnswerDetail.objects.select_related('question').filter(examrecord=er).order_by('id').values('id', 'question__right', 'total_score', 'question__type')
|
||||
total_score = 0
|
||||
try:
|
||||
for index, ad in enumerate(ads):
|
||||
ad.user_answer = questions_[index]['user_answer']
|
||||
if ad.question__type == '多选':
|
||||
if set(ad.question__right) == set(ad.user_answer):
|
||||
ad.is_right = True
|
||||
ad.score = ad.total_score
|
||||
else:
|
||||
if ad.question__right == ad.user_answer:
|
||||
ad.is_right = True
|
||||
ad.score = ad.total_score
|
||||
ad.save()
|
||||
total_score = total_score + ad.score
|
||||
except Exception as e:
|
||||
raise ParseError('判卷失败, 请检查试卷:' + str(e))
|
||||
er.score = total_score
|
||||
if er.score > 0.6*er.total_score:
|
||||
er.is_pass = True
|
||||
er.took = (now - er.create_time).total_seconds()
|
||||
er.end_time = now
|
||||
er.is_submited = True
|
||||
er.save()
|
||||
return Response()
|
Loading…
Reference in New Issue