# coding=utf-8 import json import traceback from django.db.models import Sum, F from rest_framework.decorators import action from rest_framework.serializers import ValidationError from rest_framework.views import APIView from django.db import transaction from django.db.models import Q from utils.custom_modelviewset import CustomModelViewSet from utils import response_ok, response_error from utils.permission import IsAdministrator, IsStaff from apps.examination.examquestion.serializers import * from apps.examination.examquestion.filters import * from apps.system.models import SysLog from apps.foundation.serializers import SubjectSerializer, ChapterSerializer, SubjectSimpleSerializer, \ ChapterSimpleSerializer, Subject from apps.practise.practiselog.models import * from apps.practise.practiselog.serializers import PractiseLogSerializer class PractiseLogViewSet(CustomModelViewSet): permission_classes = [IsStaff, ] queryset = PractiseLog.objects.filter() serializer_class = PractiseLogSerializer def filter_queryset(self, queryset): queryset = queryset.filter(create_user=self.request.user) return queryset def create(self, request, *args, **kwargs): subject = request.data.get('subject') chapter = request.data.get('chapter') type = PractiseLog.CHAPTER try: with transaction.atomic(): if not chapter: # 进入练习题,没有选择章节,使用该科目下的第一个章节 # chapter = Chapter.objects.filter(subject=subject, delete=False).order_by('id').first() type = PractiseLog.SUBJECT data = { 'subject': int(subject), 'chapter': chapter and int(chapter) or None, 'type': type, 'create_user': request.user.id, 'submit_time': timezone.now() } serializer = PractiseLogSerializer(data=data) if serializer.is_valid(raise_exception=True): instance = serializer.save() result = { 'practise': instance.id, # 练习题 id } return response_ok(result) except ValidationError as e: traceback.print_exc() return response_error('数据格式有误') @action(methods=['post'], detail=True) def get_next_practise(self, request, pk): now_practise = request.data.get('now_practise') # 当前提交的练习题, 第一题或继续答题时,该参数为空 answers = json.loads(request.data.get('answers')) # 答案, 第一题或继续答题时,该参数为空 next_number = int(request.data.get('next_number')) # 下一题序号,最后一题提交时,此参数为0 next_type = int(request.data.get('next_type')) # 下一题题型,默认1为单选题 button_type = request.data.get('button_type') # 上一题、下一题按钮类型,next下一题,previous上一题 previous_practise = request.data.get('previous_practise') # 上一题id try: with transaction.atomic(): instance = self.get_object() # 点击下一题,保存、判断当前习题答案 if now_practise and button_type == 'next': if len(answers) == 0: raise CustomError('请选择该题的答案!') now_question = ExamQuestion.objects.filter(id=now_practise).first() if not now_question: raise CustomError('提交的习题有误,请刷新重试!') answer_log, create = PractiseAnswerLog.objects.get_or_create(main=instance, question=now_question, status=PractiseAnswerLog.WRONG) if now_question.type == ExamQuestion.SINGLE: # 单选 if len(answers) != 1: raise CustomError(u'请提交一个答案!') answer = answers[0] PractiseAnswerOptionLog.objects.create(main=answer_log, option_id=answer) right = ExamQuestionOption.objects.filter(main=now_question, id=answer, right=True, ) if right: instance.right_count += 1 answer_log.status = PractiseAnswerLog.RIGHT else: instance.wrong_count += 1 elif now_question.type == ExamQuestion.MULTIPLE: # 多选 if len(answers) <= 1: raise CustomError(u'请提交两个以上答案!') answers.sort() for a in answers: PractiseAnswerOptionLog.objects.create(main=answer_log, option_id=a) right = ExamQuestionOption.objects.filter(main=now_question, right=True, delete=False).values_list('id', flat=True) right.sort() if answers == right: answer_log.status = PractiseAnswerLog.RIGHT instance.right_count += 1 else: instance.wrong_count += 1 elif now_question.type == ExamQuestion.FILL: # 填空 answers_len = len(answers) right = 1 for a in range(1, answers_len): PractiseAnswerFillLog.objects.create(main=answer_log, content=answers[a], order=a) right_answer = ExamQuestionFill.objects.filter(main=now_question, content=answers[a], order=a) if not right_answer: # 有一个填空错误,整题错误 right = 0 if right: answer_log.status = PractiseAnswerLog.RIGHT instance.right_count += 1 else: instance.wrong_count += 1 else: # 判断 if now_question.judgment == (answers[0] == 1): answer_log.status = PractiseAnswerLog.RIGHT instance.right_count += 1 else: instance.wrong_count += 1 instance.total_count += 1 # 第一题 if next_number == 1: instance.begin_answer = answer_log instance.end_answer = answer_log instance.submit_time = timezone.now() instance.save() answer_log.order = next_number answer_log.save() question_data = {} if previous_practise: # 上一题 questions = ExamQuestion.objects.filter(id=previous_practise) elif instance.type == PractiseLog.SUBJECT: questions = ExamQuestion.objects.filter(chapter__subject=instance.subject, delete=False).order_by( 'type') else: questions = ExamQuestion.objects.filter(chapter=instance.chapter, delete=False).order_by('type') # 返回下一题 if next_number: # 循环查询4个题型的试题,只到查询到试题 # question = None # while not question and next_type <= ExamQuestion.JUDGMENT: # question = questions.filter(type=int(next_type))[next_number - 1:next_number].first() # if question: # break # next_type += 1 # next_number = 1 question = questions.filter()[next_number - 1:next_number].first() if question: # 查询到下一题,返回题目和答案 # 根据下一题,查询下下一题类型 # next_question = None # while not next_question and next_type <= ExamQuestion.JUDGMENT: # next_question = questions.filter(type=int(next_type))[next_number:next_number + 1].first() # if next_question: # if next_number == 0: # next_number = 1 # break # next_type += 1 # next_number = 0 # next_question = questions.filter()[next_number:next_number + 1] # if next_question: # next_number += 1 # else: # next_number = 0 question_data = { 'id': question.id, 'title': question.title, 'next_type': question.type, # 下一题类别 id,不在使用 'next_number': next_number + 1, # 下下一题序号,如果为0,则没有下一题了 'previous_practise': now_practise, # 上一题 id 'option': [], } answer_log = PractiseAnswerLog.objects.filter(main=instance, question=question).first() if question.type == ExamQuestion.JUDGMENT: item1 = { 'id': 1, 'content': '正确', 'answer': True if answer_log.status == PractiseAnswerLog.RIGHT else False } item0 = { 'id': 0, 'content': '错误', 'answer': True if answer_log.status == PractiseAnswerLog.WRONG else False } question_data['option'].append(item1) question_data['option'].append(item0) elif question.type <= ExamQuestion.MULTIPLE: rows = ExamQuestionOption.objects.filter(main=question, delete=False) for row in rows: option_log = PractiseAnswerOptionLog.objects.filter(main=answer_log, option=row).first() item = { 'id':row.id, 'content':row.content, 'answer': option_log and True or False } question_data['option'].append(item) elif question.type == ExamQuestion.FILL: rows = ExamQuestionFill.objects.filter(main=question, delete=False) for row in rows: option_log = PractiseAnswerFillLog.objects.filter(main=answer_log, order=row.order).first() item = { 'id':row.order, # 填空题序号 'content':option_log and option_log.content or '', } question_data['option'].append(item) # 右侧习题类别列表 # 单选题 questions = questions.values_list('id', flat=True) single_questions_list = [] for single in questions.filter(type=ExamQuestion.SINGLE): answer_log = PractiseAnswerLog.objects.filter(main=instance, question_id=single) single_questions_list.append( { 'question_id':single, 'complete':answer_log and True or False, } ) # 多选题 multiple_questions_list = [] for multiple in questions.filter(type=ExamQuestion.MULTIPLE): answer_log = PractiseAnswerLog.objects.filter(main=instance, question_id=multiple) multiple_questions_list.append( { 'question_id':multiple, 'complete':answer_log and True or False, } ) # 填空题 fill_questions_list = [] for fill in questions.filter(type=ExamQuestion.FILL): answer_log = PractiseAnswerLog.objects.filter(main=instance, question_id=fill) fill_questions_list.append( { 'question_id':fill, 'complete':answer_log and True or False, } ) # 判断题 judgment_questions_list = [] for judgment in questions.filter(type=ExamQuestion.MULTIPLE): answer_log = PractiseAnswerLog.objects.filter(main=instance, question_id=judgment) judgment_questions_list.append( { 'question_id':judgment, 'complete':answer_log and True or False, } ) result = { 'question_data': question_data, # 下一题练习题 'single_questions_list': single_questions_list, # 单选 'multiple_questions_list': multiple_questions_list, # 多选 'fill_questions_list': fill_questions_list, # 填空 'judgment_questions_list': judgment_questions_list, # 判断 } return response_ok(result) except CustomError as e: return response_error(e.get_error_msg()) except Exception as e: traceback.print_exc() return response_error(str(e)) class DictView(APIView): permission_classes = [IsStaff, ] def get(self, request): data = [] subjects = Subject.objects.filter(delete=False).values('id', 'name').order_by('id') for subject in subjects: chapters = ChapterSimpleSerializer( Chapter.objects.filter(delete=False, subject__delete=False, subject_id=subject['id']).order_by('id'), many=True).data item = { 'id': subject['id'], 'name': subject['name'], 'chapters': chapters, } data.append(item) return response_ok(data)