diff --git a/server/apps/exam/filters.py b/server/apps/exam/filters.py new file mode 100644 index 0000000..7561fc0 --- /dev/null +++ b/server/apps/exam/filters.py @@ -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'] \ No newline at end of file diff --git a/server/apps/exam/migrations/0002_auto_20221107_1356.py b/server/apps/exam/migrations/0002_auto_20221107_1356.py new file mode 100644 index 0000000..dc77a2c --- /dev/null +++ b/server/apps/exam/migrations/0002_auto_20221107_1356.py @@ -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'), + ), + ] diff --git a/server/apps/exam/models.py b/server/apps/exam/models.py index 6c3cc0c..dd35c3f 100644 --- a/server/apps/exam/models.py +++ b/server/apps/exam/models.py @@ -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 \ No newline at end of file + verbose_name_plural = verbose_name + \ No newline at end of file diff --git a/server/apps/exam/serializers.py b/server/apps/exam/serializers.py index fe2e326..3ac83b2 100644 --- a/server/apps/exam/serializers.py +++ b/server/apps/exam/serializers.py @@ -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="考试编号") \ No newline at end of file + 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'] diff --git a/server/apps/exam/views.py b/server/apps/exam/views.py index a69cac7..c0c4461 100644 --- a/server/apps/exam/views.py +++ b/server/apps/exam/views.py @@ -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() \ No newline at end of file