Browse Source

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	apps/api/staff/urls.py
jiaweiqi 3 years ago
parent
commit
bab4c19fcd

+ 14 - 0
apps/api/staff/mock/urls.py

@@ -0,0 +1,14 @@
+# coding=utf-8
+from django.conf.urls import url, include
+from rest_framework.routers import SimpleRouter
+
+from .views import *
+
+urlpatterns = [
+    url(r'^dict/$', DictView.as_view()),
+]
+
+router = SimpleRouter()
+router.register(r'exam_paper', ExamPaperViewSet)
+# router.register(r'exam', ExamLogViewSet)
+urlpatterns += router.urls

+ 46 - 0
apps/api/staff/mock/views.py

@@ -0,0 +1,46 @@
+# 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.exam.serializers import *
+from apps.examination.exam.filters import *
+from apps.system.models import SysLog
+from apps.foundation.serializers import SubjectSerializer, ChapterSerializer, SubjectSimpleSerializer, \
+    ChapterSimpleSerializer, Subject
+from apps.examination.exampaper.filters import ExamPaper, ExamPaperFilter
+from apps.examination.exampaper.serializers import StaffExamPaperSerializer
+
+class ExamPaperViewSet(CustomModelViewSet):
+    permission_classes = [IsStaff, ]
+    queryset = ExamPaper.objects.filter(delete=False)
+    serializer_class = StaffExamPaperSerializer
+
+    def filter_queryset(self, queryset):
+        f = ExamPaperFilter(self.request.GET, queryset=queryset, request=self.request)
+        return f.qs
+
+class ExamLogViewSet(CustomModelViewSet):
+    permission_classes = [IsStaff, ]
+    queryset = ExamLog.objects.filter(delete=False)
+    serializer_class = StaffExamLogSerializer
+
+    def filter_queryset(self, queryset):
+        # queryset = queryset.filter(user=self.request.user)
+        f = FormalExamLogFilter(self.request.GET, queryset=queryset)
+        return f.qs
+
+class DictView(APIView):
+    permission_classes = [IsStaff, ]
+
+    def get(self, request):
+        subjects = Subject.objects.filter(delete=False)
+        serializers = SubjectSerializer(subjects, many=True)
+        return response_ok(serializers.data)

+ 92 - 64
apps/api/staff/practise/views.py

@@ -50,7 +50,7 @@ class PractiseLogViewSet(CustomModelViewSet):
                 if serializer.is_valid(raise_exception=True):
                     instance = serializer.save()
                     result = {
-                        'practise': instance.id, # 练习题 id
+                        'practise': instance.id,  # 练习题 id
                     }
                     return response_ok(result)
         except ValidationError as e:
@@ -61,8 +61,8 @@ class PractiseLogViewSet(CustomModelViewSet):
     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')) or 0  # 下一题序号, 第一题提交为空
-        next_practise = request.data.get('next_practise')  #  下一题id,首次加载第一题,传空
+        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()
@@ -72,19 +72,19 @@ class PractiseLogViewSet(CustomModelViewSet):
                     if not now_question:
                         raise CustomError('提交的习题有误,请刷新重试!')
                     if len(answers) > 0:
-                        answer_log, create = PractiseAnswerLog.objects.get_or_create(main=instance, question=now_question,)
+                        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 )
+                            right = ExamQuestionOption.objects.filter(main=now_question, id=answer, right=True,
+                                                                      delete=False)
                             if right:
-                                instance.right_count += 1
                                 answer_log.status = PractiseAnswerLog.RIGHT
                             else:
                                 answer_log.status = PractiseAnswerLog.WRONG
-                                instance.wrong_count += 1
                         elif now_question.type == ExamQuestion.MULTIPLE:
                             # 多选
                             answers.sort()
@@ -96,35 +96,30 @@ class PractiseLogViewSet(CustomModelViewSet):
                             list(right).sort()
                             if answers == right:
                                 answer_log.status = PractiseAnswerLog.RIGHT
-                                instance.right_count += 1
                             else:
                                 answer_log.status = PractiseAnswerLog.WRONG
-                                instance.wrong_count += 1
                         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)
+                                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
-                                instance.right_count += 1
                             else:
                                 answer_log.status = PractiseAnswerLog.WRONG
-                                instance.wrong_count += 1
                         else:
                             # 判断
                             if now_question.judgment == (answers[0] == 1):
                                 answer_log.status = PractiseAnswerLog.RIGHT
-                                instance.right_count += 1
                             else:
                                 answer_log.status = PractiseAnswerLog.WRONG
-                                instance.wrong_count += 1
                         instance.total_count += 1
                         # 第一题
                         if not instance.begin_answer:
@@ -133,6 +128,16 @@ class PractiseLogViewSet(CustomModelViewSet):
                         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:
@@ -140,7 +145,6 @@ class PractiseLogViewSet(CustomModelViewSet):
                         'type')
                 else:
                     questions = ExamQuestion.objects.filter(chapter=instance.chapter, delete=False).order_by('type')
-
                 # 返回下一题
                 if next_practise:
                     question = questions.filter(id=next_practise).first()
@@ -149,77 +153,80 @@ class PractiseLogViewSet(CustomModelViewSet):
                     question = questions.filter().first()
 
                 if question:
-                        question_data = {
-                            'id': question.id,
-                            'title': question.title,
-                            'next_type': question.type,  # 下一题习题类别
-                            'next_number': next_number + 1,  # 下下一题序号,
-                            'option': [],
+                    question_data = {
+                        'id': question.id,
+                        'title': question.title,
+                        '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
                         }
-                        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
                             }
-                            item0 = {
-                                'id': 0,
-                                'content': '错误',
-                                'answer': True if answer_log and answer_log.status == PractiseAnswerLog.WRONG else 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(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)
+                            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)
+                    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,
+                            '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)
+                    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,
+                            '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)
+                    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,
+                            'question_id': fill,
+                            'complete': answer_log and True or False,
                         }
                     )
                 # 判断题
@@ -228,8 +235,8 @@ class PractiseLogViewSet(CustomModelViewSet):
                     answer_log = PractiseAnswerLog.objects.filter(main=instance, question_id=judgment)
                     judgment_questions_list.append(
                         {
-                            'question_id':judgment,
-                            'complete':answer_log and True or False,
+                            'question_id': judgment,
+                            'complete': answer_log and True or False,
                         }
                     )
                 result = {
@@ -246,6 +253,27 @@ class PractiseLogViewSet(CustomModelViewSet):
             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, ]
 

+ 1 - 0
apps/api/staff/urls.py

@@ -11,5 +11,6 @@ urlpatterns = [
     url(r'^token_verify/$', StaffUserVerifyTokenView.as_view()),
 
     url(r'^practise/', include('apps.api.staff.practise.urls')),
+    url(r'^mock/', include('apps.api.staff.mock.urls')),
     url(r'^errorbook/', include('apps.api.staff.errorbook.urls')),
 ]

+ 11 - 1
apps/examination/exampaper/filters.py

@@ -7,7 +7,17 @@ class ExamPaperFilter(django_filters.FilterSet):
     name = django_filters.CharFilter(field_name="name", lookup_expr="icontains")
     subject = django_filters.CharFilter(field_name='subject_id')
     type = django_filters.CharFilter(field_name='type')
+    status = django_filters.CharFilter(method='status_filter')
+
+    def status_filter(self, queryset, name,value):
+        from apps.examination.exam.models import ExamLog
+        exampaper_ids = ExamLog.objects.filter(user=self.request.user, delete=False).values_list('exampaper_id', flat=True)
+        if value == '1':
+            queryset = queryset.filter(id__in=exampaper_ids)
+        elif value == '2':
+            queryset = queryset.exclude(id__in=exampaper_ids)
+        return queryset
 
     class Meta:
         model = ExamPaper
-        fields = "__all__"
+        fields = "__all__"

+ 16 - 1
apps/examination/exampaper/serializers.py

@@ -80,4 +80,19 @@ class ExamPaperSerializer(serializers.ModelSerializer):
             instance.clear_detail()
             instance.generate_detail()
 
-        return instance
+        return instance
+
+class StaffExamPaperSerializer(serializers.ModelSerializer):
+    subject_name = serializers.CharField(source='subject.name', read_only=True)
+    status_text = serializers.SerializerMethodField()
+
+    def get_status_text(self, obj):
+        from apps.examination.exam.models import ExamLog
+        exampaper = ExamLog.objects.filter(user=self.context['request'].user,exampaper=obj)
+        if exampaper:
+            return '做过'
+        return ''
+
+    class Meta:
+        model = ExamPaper
+        fields = ('id', 'name','subject_name','status_text','did_count','question_total_count', )

+ 34 - 5
apps/practise/practiselog/serializers.py

@@ -14,7 +14,15 @@ class PractiseLogSerializer(serializers.ModelSerializer):
         if obj.end_answer:
             now_type = obj.end_answer.question.type
             questions = ExamQuestion.objects.filter(type=now_type, delete=False).order_by('id').values_list('id', flat=True)
-            now_question_index = list(questions).index(obj.end_answer.question.id)
+            if obj.chapter:
+                questions = questions.filter(chapter=obj.chapter)
+            else:
+                questions = questions.filter(chapter__subject=obj.subject)
+            try:
+                # ValueError: 1 is not in list
+                now_question_index = list(questions).index(obj.end_answer.question.id)
+            except ValueError:
+                now_question_index = 0
             if now_question_index < (len(questions) -1):
                 # 该题型未练习完,继续返回该题型下的习题
                 next_practise = questions[now_question_index + 1]
@@ -22,7 +30,12 @@ class PractiseLogSerializer(serializers.ModelSerializer):
                 # 该题型已练习完,返回下一个题型下的习题
                 while now_type <= ExamQuestion.JUDGMENT:
                     now_type += 1
-                    questions = ExamQuestion.objects.filter(type=now_type, delete=False).order_by('id').first()
+                    questions = ExamQuestion.objects.filter(type=now_type, delete=False)
+                    if obj.chapter:
+                        questions = questions.filter(chapter=obj.chapter)
+                    else:
+                        questions = questions.filter(chapter__subject=obj.subject)
+                    questions = questions.order_by('id').first()
                     if questions:
                         next_practise = questions.id
                         break
@@ -31,9 +44,17 @@ class PractiseLogSerializer(serializers.ModelSerializer):
     def get_end_answer(self, obj):
         if obj.end_answer:
             now_type = obj.end_answer.question.type
-            # todo
+            # todo 按id查
             questions = ExamQuestion.objects.filter(type=now_type, delete=False).order_by('id').values_list('id', flat=True)
-            now_question_index = list(questions).index(obj.end_answer.question.id)
+            if obj.chapter:
+                questions = questions.filter(chapter=obj.chapter)
+            else:
+                questions = questions.filter(chapter__subject=obj.subject)
+            try:
+                # ValueError: 1 is not in list
+                now_question_index = list(questions).index(obj.end_answer.question.id)
+            except ValueError:
+                now_question_index = 0
             name = '{0}/{1} {2}第{3}题'.format(obj.end_answer.question.chapter.name,
                                          obj.end_answer.question.chapter.subject.name,
                                          ExamQuestion.TYPE_CHOICES[obj.end_answer.question.type - 1][1],
@@ -46,7 +67,15 @@ class PractiseLogSerializer(serializers.ModelSerializer):
         if obj.begin_answer:
             now_type = obj.begin_answer.question.type
             questions = ExamQuestion.objects.filter(type=now_type, delete=False).order_by('id').values_list('id', flat=True)
-            now_question_index = list(questions).index(obj.begin_answer.question.id)
+            if obj.chapter:
+                questions = questions.filter(chapter=obj.chapter)
+            else:
+                questions = questions.filter(chapter__subject=obj.subject)
+            try:
+                # ValueError: 1 is not in list
+                now_question_index = list(questions).index(obj.begin_answer.question.id)
+            except ValueError:
+                now_question_index = 0
             name = '{0}/{1} {2}第{3}题'.format(obj.begin_answer.question.chapter.name,
                                          obj.begin_answer.question.chapter.subject.name,
                                          ExamQuestion.TYPE_CHOICES[obj.begin_answer.question.type - 1][1],