123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- # 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 = request.data.get('next_number') or 0 # 下一题序号, 第一题提交为空,不在使用
- next_practise = request.data.get('next_practise') # 下一题id,首次加载第一题,传空
- try:
- with transaction.atomic():
- instance = self.get_object()
- # 点击下一题,保存、判断当前习题答案
- if now_practise:
- now_question = ExamQuestion.objects.filter(id=now_practise).first()
- if not now_question:
- raise CustomError('提交的习题有误,请刷新重试!')
- if len(answers) > 0:
- answer_log, create = PractiseAnswerLog.objects.get_or_create(main=instance,
- question=now_question, )
- if now_question.type == ExamQuestion.SINGLE:
- # 单选
- PractiseAnswerOptionLog.objects.filter(main=answer_log).delete()
- answer = answers[0]
- PractiseAnswerOptionLog.objects.create(main=answer_log, option_id=answer)
- right = ExamQuestionOption.objects.filter(main=now_question, id=answer, right=True,
- delete=False)
- if right:
- answer_log.status = PractiseAnswerLog.RIGHT
- else:
- answer_log.status = PractiseAnswerLog.WRONG
- elif now_question.type == ExamQuestion.MULTIPLE:
- # 多选
- answers.sort()
- PractiseAnswerOptionLog.objects.filter(main=answer_log).delete()
- 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)
- list(right).sort()
- if answers == right:
- answer_log.status = PractiseAnswerLog.RIGHT
- else:
- answer_log.status = PractiseAnswerLog.WRONG
- elif now_question.type == ExamQuestion.FILL:
- # 填空
- answers_len = len(answers)
- right = 1
- PractiseAnswerFillLog.objects.filter(main=answer_log).delete()
- for a in range(0, answers_len):
- PractiseAnswerFillLog.objects.create(main=answer_log, content=answers[a], order=a + 1)
- right_answer = ExamQuestionFill.objects.filter(main=now_question, content=answers[a],
- order=a + 1)
- if not right_answer:
- # 有一个填空错误,整题错误
- right = 0
- if right:
- answer_log.status = PractiseAnswerLog.RIGHT
- else:
- answer_log.status = PractiseAnswerLog.WRONG
- else:
- # 判断
- if now_question.judgment == (answers[0] == 1):
- answer_log.status = PractiseAnswerLog.RIGHT
- else:
- answer_log.status = PractiseAnswerLog.WRONG
- instance.total_count += 1
- # 第一题
- if not instance.begin_answer:
- instance.begin_answer = answer_log
- instance.end_answer = answer_log
- instance.submit_time = timezone.now()
- instance.save()
- answer_log.save()
- else:
- try:
- answer_log = PractiseAnswerLog.objects.get(main=instance, question=now_question, )
- PractiseAnswerOptionLog.objects.filter(main=answer_log).delete()
- PractiseAnswerFillLog.objects.filter(main=answer_log).delete()
- answer_log.status = None
- answer_log.save()
- except PractiseAnswerLog.DoesNotExist:
- # traceback.print_exc()
- pass
- question_data = {}
- if 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_practise:
- question = questions.filter(id=next_practise).first()
- else:
- # 首次加载,选择第一个题
- question = questions.filter().first()
- if question:
- question_data = {
- 'id': question.id,
- 'title': question.title,
- 'create_time': instance.create_time.strftime('%Y-%m-%d %H:%M:%S'),
- 'next_type': question.type, # 下一题习题类别
- 'next_number': int(next_number) + 1, # 下下一题序号,
- '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 and answer_log.status == PractiseAnswerLog.RIGHT else False
- }
- item0 = {
- 'id': 0,
- 'content': '错误',
- 'answer': True if answer_log and 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)
- # 右侧习题类别列表
- # 单选题
- # 单选、多选、填空。选择答案后,可能会把答案清空,得加上status__isnull=False过滤
- 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,
- status__isnull=False)
- 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,
- status__isnull=False)
- 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, status__isnull=False)
- fill_questions_list.append(
- {
- 'question_id': fill,
- 'complete': answer_log and True or False,
- }
- )
- # 判断题
- judgment_questions_list = []
- for judgment in questions.filter(type=ExamQuestion.JUDGMENT):
- 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))
- @action(methods=['post'], detail=True)
- def submit_practise(self, request, pk):
- # 习题交卷,把上个接口的判断答案,放到此处
- try:
- instance = self.get_object()
- with transaction.atomic():
- right_count = PractiseAnswerLog.objects.filter(main=instance, status=PractiseAnswerLog.RIGHT).count()
- wrong_count = PractiseAnswerLog.objects.filter(main=instance, status=PractiseAnswerLog.WRONG).count()
- instance.right_count = right_count
- instance.wrong_count = wrong_count
- instance.submit_time = timezone.now()
- instance.save()
- SysLog.objects.addnew(request.user, SysLog.INSERT, u"提交习题答案,id=%d" % (instance.id))
- 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 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)
|