|
@@ -1,5 +1,6 @@
|
|
# coding=utf-8
|
|
# coding=utf-8
|
|
import json
|
|
import json
|
|
|
|
+import traceback
|
|
from django.db.models import Sum, F
|
|
from django.db.models import Sum, F
|
|
from rest_framework.decorators import action
|
|
from rest_framework.decorators import action
|
|
from rest_framework.views import APIView
|
|
from rest_framework.views import APIView
|
|
@@ -9,9 +10,11 @@ from django.db.models import Q
|
|
from utils.custom_modelviewset import CustomModelViewSet
|
|
from utils.custom_modelviewset import CustomModelViewSet
|
|
from utils import response_ok, response_error
|
|
from utils import response_ok, response_error
|
|
from utils.permission import IsAdministrator
|
|
from utils.permission import IsAdministrator
|
|
|
|
+from utils.format import ExcelImporter
|
|
from apps.examination.examquestion.serializers import *
|
|
from apps.examination.examquestion.serializers import *
|
|
from apps.examination.examquestion.filters import *
|
|
from apps.examination.examquestion.filters import *
|
|
from apps.system.models import SysLog
|
|
from apps.system.models import SysLog
|
|
|
|
+from apps.foundation.models import Subject, Chapter
|
|
|
|
|
|
class ExamQuestionViewSet(CustomModelViewSet):
|
|
class ExamQuestionViewSet(CustomModelViewSet):
|
|
permission_classes = [IsAdministrator, ]
|
|
permission_classes = [IsAdministrator, ]
|
|
@@ -49,6 +52,337 @@ class ExamQuestionViewSet(CustomModelViewSet):
|
|
SysLog.objects.addnew(request.user, SysLog.INSERT, u"删除试题库试题,id=%d" % instance.id)
|
|
SysLog.objects.addnew(request.user, SysLog.INSERT, u"删除试题库试题,id=%d" % instance.id)
|
|
return response_ok()
|
|
return response_ok()
|
|
|
|
|
|
|
|
+ @action(methods=['post'], detail=False)
|
|
|
|
+ def import_single(self, request):
|
|
|
|
+ file = request.FILES.get('excel_file')
|
|
|
|
+ status = ExcelImporter.validity(file)
|
|
|
|
+ if not status['success']:
|
|
|
|
+ return response_error(status['errors'])
|
|
|
|
+
|
|
|
|
+ data = status['data']
|
|
|
|
+ question_count = 0
|
|
|
|
+ line = 2
|
|
|
|
+ try:
|
|
|
|
+ with transaction.atomic():
|
|
|
|
+ cur_question = None
|
|
|
|
+ for row in data:
|
|
|
|
+ title = row['试题内容']
|
|
|
|
+ subject = row['科目']
|
|
|
|
+ chapter = row['章节']
|
|
|
|
+ difficulty_text = row['难度']
|
|
|
|
+ scores= row['分数']
|
|
|
|
+ analysis = row['解析']
|
|
|
|
+ content = row['选项']
|
|
|
|
+ right = row['正确答案']
|
|
|
|
+
|
|
|
|
+ if title and content:
|
|
|
|
+ raise CustomError(u'第%d行:数据格式不正确' % line)
|
|
|
|
+ if title and not content:
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目不能为空' % line)
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节不能为空' % line)
|
|
|
|
+ if not difficulty_text:
|
|
|
|
+ raise CustomError(u'第%d行:难度不能为空' % line)
|
|
|
|
+ if not scores:
|
|
|
|
+ raise CustomError(u'第%d行:分数不能为空' % line)
|
|
|
|
+
|
|
|
|
+ if difficulty_text == u'简单':
|
|
|
|
+ difficulty = ExamQuestion.SIMPLE
|
|
|
|
+ elif difficulty_text == u'中等':
|
|
|
|
+ difficulty = ExamQuestion.MID
|
|
|
|
+ elif difficulty_text == u'困难':
|
|
|
|
+ difficulty = ExamQuestion.HARD
|
|
|
|
+ else:
|
|
|
|
+ raise CustomError(u'第%d行:难度为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ subject = Subject.objects.filter(name=subject, delete=False).first()
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目为无效数据' % line)
|
|
|
|
+ chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节为无效数据' % line)
|
|
|
|
+ try:
|
|
|
|
+ scores = int(scores)
|
|
|
|
+ except:
|
|
|
|
+ raise CustomError(u'第%d行:分数为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ cur_question = ExamQuestion.objects.create(
|
|
|
|
+ chapter=chapter,
|
|
|
|
+ type=ExamQuestion.SINGLE,
|
|
|
|
+ difficulty=difficulty,
|
|
|
|
+ scores=scores,
|
|
|
|
+ title=title,
|
|
|
|
+ analysis=analysis,
|
|
|
|
+ create_user=request.user,
|
|
|
|
+ create_time=timezone.now()
|
|
|
|
+ )
|
|
|
|
+ question_count += 1
|
|
|
|
+ if content and not title:
|
|
|
|
+ if not cur_question:
|
|
|
|
+ continue
|
|
|
|
+ if right:
|
|
|
|
+ ExamQuestionOption.objects.create(main=cur_question, content=content, right=True)
|
|
|
|
+ else:
|
|
|
|
+ ExamQuestionOption.objects.create(main=cur_question, content=content)
|
|
|
|
+
|
|
|
|
+ line += 1
|
|
|
|
+ SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道单选题" % (question_count))
|
|
|
|
+ except CustomError as e:
|
|
|
|
+ return response_error(e.get_error_msg())
|
|
|
|
+ except Exception as e:
|
|
|
|
+ traceback.print_exc()
|
|
|
|
+ return response_error(str(e))
|
|
|
|
+ return response_ok()
|
|
|
|
+
|
|
|
|
+ @action(methods=['post'], detail=False)
|
|
|
|
+ def import_multiple(self, request):
|
|
|
|
+ file = request.FILES.get('excel_file')
|
|
|
|
+ status = ExcelImporter.validity(file)
|
|
|
|
+ if not status['success']:
|
|
|
|
+ return response_error(status['errors'])
|
|
|
|
+
|
|
|
|
+ data = status['data']
|
|
|
|
+ question_count = 0
|
|
|
|
+ line = 2
|
|
|
|
+ try:
|
|
|
|
+ with transaction.atomic():
|
|
|
|
+ cur_question = None
|
|
|
|
+ for row in data:
|
|
|
|
+ title = row['试题内容']
|
|
|
|
+ subject = row['科目']
|
|
|
|
+ chapter = row['章节']
|
|
|
|
+ difficulty_text = row['难度']
|
|
|
|
+ scores = row['分数']
|
|
|
|
+ analysis = row['解析']
|
|
|
|
+ content = row['选项']
|
|
|
|
+ right = row['正确答案']
|
|
|
|
+
|
|
|
|
+ if title and content:
|
|
|
|
+ raise CustomError(u'第%d行:数据格式不正确' % line)
|
|
|
|
+ if title and not content:
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目不能为空' % line)
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节不能为空' % line)
|
|
|
|
+ if not difficulty_text:
|
|
|
|
+ raise CustomError(u'第%d行:难度不能为空' % line)
|
|
|
|
+ if not scores:
|
|
|
|
+ raise CustomError(u'第%d行:分数不能为空' % line)
|
|
|
|
+
|
|
|
|
+ if difficulty_text == u'简单':
|
|
|
|
+ difficulty = ExamQuestion.SIMPLE
|
|
|
|
+ elif difficulty_text == u'中等':
|
|
|
|
+ difficulty = ExamQuestion.MID
|
|
|
|
+ elif difficulty_text == u'困难':
|
|
|
|
+ difficulty = ExamQuestion.HARD
|
|
|
|
+ else:
|
|
|
|
+ raise CustomError(u'第%d行:难度为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ subject = Subject.objects.filter(name=subject, delete=False).first()
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目为无效数据' % line)
|
|
|
|
+ chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节为无效数据' % line)
|
|
|
|
+ try:
|
|
|
|
+ scores = int(scores)
|
|
|
|
+ except:
|
|
|
|
+ raise CustomError(u'第%d行:分数为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ cur_question = ExamQuestion.objects.create(
|
|
|
|
+ chapter=chapter,
|
|
|
|
+ type=ExamQuestion.MULTIPLE,
|
|
|
|
+ difficulty=difficulty,
|
|
|
|
+ scores=scores,
|
|
|
|
+ title=title,
|
|
|
|
+ analysis=analysis,
|
|
|
|
+ create_user=request.user,
|
|
|
|
+ create_time=timezone.now()
|
|
|
|
+ )
|
|
|
|
+ question_count += 1
|
|
|
|
+ if content and not title:
|
|
|
|
+ if not cur_question:
|
|
|
|
+ continue
|
|
|
|
+ if right:
|
|
|
|
+ ExamQuestionOption.objects.create(main=cur_question, content=content, right=True)
|
|
|
|
+ else:
|
|
|
|
+ ExamQuestionOption.objects.create(main=cur_question, content=content)
|
|
|
|
+
|
|
|
|
+ line += 1
|
|
|
|
+ SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道多选题" % (question_count))
|
|
|
|
+ except CustomError as e:
|
|
|
|
+ return response_error(e.get_error_msg())
|
|
|
|
+ except Exception as e:
|
|
|
|
+ traceback.print_exc()
|
|
|
|
+ return response_error(str(e))
|
|
|
|
+ return response_ok()
|
|
|
|
+
|
|
|
|
+ @action(methods=['post'], detail=False)
|
|
|
|
+ def import_fill(self, request):
|
|
|
|
+ file = request.FILES.get('excel_file')
|
|
|
|
+ status = ExcelImporter.validity(file)
|
|
|
|
+ if not status['success']:
|
|
|
|
+ return response_error(status['errors'])
|
|
|
|
+
|
|
|
|
+ data = status['data']
|
|
|
|
+ question_count = 0
|
|
|
|
+ line = 2
|
|
|
|
+ try:
|
|
|
|
+ with transaction.atomic():
|
|
|
|
+ cur_question = None
|
|
|
|
+ order = 0
|
|
|
|
+ for row in data:
|
|
|
|
+ title = row['试题内容']
|
|
|
|
+ subject = row['科目']
|
|
|
|
+ chapter = row['章节']
|
|
|
|
+ difficulty_text = row['难度']
|
|
|
|
+ scores = row['分数']
|
|
|
|
+ analysis = row['解析']
|
|
|
|
+ content = row['答案']
|
|
|
|
+
|
|
|
|
+ if title and not content:
|
|
|
|
+ raise CustomError(u'第%d行:答案不能为空' % line)
|
|
|
|
+ if title and content:
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目不能为空' % line)
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节不能为空' % line)
|
|
|
|
+ if not difficulty_text:
|
|
|
|
+ raise CustomError(u'第%d行:难度不能为空' % line)
|
|
|
|
+ if not scores:
|
|
|
|
+ raise CustomError(u'第%d行:分数不能为空' % line)
|
|
|
|
+
|
|
|
|
+ if difficulty_text == u'简单':
|
|
|
|
+ difficulty = ExamQuestion.SIMPLE
|
|
|
|
+ elif difficulty_text == u'中等':
|
|
|
|
+ difficulty = ExamQuestion.MID
|
|
|
|
+ elif difficulty_text == u'困难':
|
|
|
|
+ difficulty = ExamQuestion.HARD
|
|
|
|
+ else:
|
|
|
|
+ raise CustomError(u'第%d行:难度为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ subject = Subject.objects.filter(name=subject, delete=False).first()
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目为无效数据' % line)
|
|
|
|
+ chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节为无效数据' % line)
|
|
|
|
+ try:
|
|
|
|
+ scores = int(scores)
|
|
|
|
+ except:
|
|
|
|
+ raise CustomError(u'第%d行:分数为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ order = 1
|
|
|
|
+ cur_question = ExamQuestion.objects.create(
|
|
|
|
+ chapter=chapter,
|
|
|
|
+ type=ExamQuestion.FILL,
|
|
|
|
+ difficulty=difficulty,
|
|
|
|
+ scores=scores,
|
|
|
|
+ title=title,
|
|
|
|
+ analysis=analysis,
|
|
|
|
+ create_user=request.user,
|
|
|
|
+ create_time=timezone.now()
|
|
|
|
+ )
|
|
|
|
+ ExamQuestionFill.objects.create(main=cur_question, content=content, order=order)
|
|
|
|
+ question_count += 1
|
|
|
|
+ order += 1
|
|
|
|
+ if content and not title:
|
|
|
|
+ if (not cur_question) or (not order):
|
|
|
|
+ continue
|
|
|
|
+ ExamQuestionFill.objects.create(main=cur_question, content=content, order=order)
|
|
|
|
+ order += 1
|
|
|
|
+
|
|
|
|
+ line += 1
|
|
|
|
+ SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道填空题" % (question_count))
|
|
|
|
+ except CustomError as e:
|
|
|
|
+ return response_error(e.get_error_msg())
|
|
|
|
+ except Exception as e:
|
|
|
|
+ traceback.print_exc()
|
|
|
|
+ return response_error(str(e))
|
|
|
|
+ return response_ok()
|
|
|
|
+
|
|
|
|
+ @action(methods=['post'], detail=False)
|
|
|
|
+ def import_judgment(self, request):
|
|
|
|
+ file = request.FILES.get('excel_file')
|
|
|
|
+ status = ExcelImporter.validity(file)
|
|
|
|
+ if not status['success']:
|
|
|
|
+ return response_error(status['errors'])
|
|
|
|
+
|
|
|
|
+ data = status['data']
|
|
|
|
+ line = 2
|
|
|
|
+ try:
|
|
|
|
+ with transaction.atomic():
|
|
|
|
+ for row in data:
|
|
|
|
+ title = row['试题内容']
|
|
|
|
+ subject = row['科目']
|
|
|
|
+ chapter = row['章节']
|
|
|
|
+ difficulty_text = row['难度']
|
|
|
|
+ scores = row['分数']
|
|
|
|
+ analysis = row['解析']
|
|
|
|
+ judgment_text = row['答案']
|
|
|
|
+
|
|
|
|
+ if not title:
|
|
|
|
+ raise CustomError(u'第%d行:试题内容不能为空' % line)
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目不能为空' % line)
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节不能为空' % line)
|
|
|
|
+ if not difficulty_text:
|
|
|
|
+ raise CustomError(u'第%d行:难度不能为空' % line)
|
|
|
|
+ if not scores:
|
|
|
|
+ raise CustomError(u'第%d行:分数不能为空' % line)
|
|
|
|
+ if not judgment_text:
|
|
|
|
+ raise CustomError(u'第%d行:答案不能为空' % line)
|
|
|
|
+
|
|
|
|
+ if difficulty_text == u'简单':
|
|
|
|
+ difficulty = ExamQuestion.SIMPLE
|
|
|
|
+ elif difficulty_text == u'中等':
|
|
|
|
+ difficulty = ExamQuestion.MID
|
|
|
|
+ elif difficulty_text == u'困难':
|
|
|
|
+ difficulty = ExamQuestion.HARD
|
|
|
|
+ else:
|
|
|
|
+ raise CustomError(u'第%d行:难度为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ if judgment_text == u'正确':
|
|
|
|
+ judgment = True
|
|
|
|
+ elif judgment_text == u'错误':
|
|
|
|
+ judgment = False
|
|
|
|
+ else:
|
|
|
|
+ raise CustomError(u'第%d行:答案为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ subject = Subject.objects.filter(name=subject, delete=False).first()
|
|
|
|
+ if not subject:
|
|
|
|
+ raise CustomError(u'第%d行:科目为无效数据' % line)
|
|
|
|
+ chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
|
|
|
|
+ if not chapter:
|
|
|
|
+ raise CustomError(u'第%d行:章节为无效数据' % line)
|
|
|
|
+ try:
|
|
|
|
+ scores = int(scores)
|
|
|
|
+ except:
|
|
|
|
+ raise CustomError(u'第%d行:分数为无效数据' % line)
|
|
|
|
+
|
|
|
|
+ ExamQuestion.objects.create(
|
|
|
|
+ chapter=chapter,
|
|
|
|
+ type=ExamQuestion.JUDGMENT,
|
|
|
|
+ difficulty=difficulty,
|
|
|
|
+ scores=scores,
|
|
|
|
+ title=title,
|
|
|
|
+ judgment=judgment,
|
|
|
|
+ analysis=analysis,
|
|
|
|
+ create_user=request.user,
|
|
|
|
+ create_time=timezone.now()
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ line += 1
|
|
|
|
+ SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道判断题" % (line - 2))
|
|
|
|
+ except CustomError as e:
|
|
|
|
+ return response_error(e.get_error_msg())
|
|
|
|
+ except Exception as e:
|
|
|
|
+ traceback.print_exc()
|
|
|
|
+ return response_error(str(e))
|
|
|
|
+ return response_ok()
|
|
|
|
+
|
|
class ExamQuestionFeedbackViewSet(ReadOnlyModelViewSet):
|
|
class ExamQuestionFeedbackViewSet(ReadOnlyModelViewSet):
|
|
permission_classes = [IsAdministrator, ]
|
|
permission_classes = [IsAdministrator, ]
|
|
queryset = ExamQuestionFeedback.objects.filter().order_by('status', '-id')
|
|
queryset = ExamQuestionFeedback.objects.filter().order_by('status', '-id')
|