272 lines
11 KiB
Python
272 lines
11 KiB
Python
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 rest_framework.decorators import action
|
||
from rest_framework.response import Response
|
||
from rest_framework.permissions import IsAuthenticated
|
||
from rest_framework.exceptions import ParseError
|
||
from openpyxl import Workbook, load_workbook
|
||
from django.conf import settings
|
||
from apps.exam.models import Paper, Exam, ExamRecord, AnswerDetail
|
||
from django.utils import timezone
|
||
from django.db import transaction
|
||
|
||
# Create your views here.
|
||
|
||
|
||
def enctry(s):
|
||
k = 'ez9z3a4m*$%srn9ve_t71yd!v+&xn9@0k(e(+l6#g1h=e5i4da'
|
||
encry_str = ""
|
||
for i, j in zip(s, k):
|
||
# i为字符,j为秘钥字符
|
||
temp = str(ord(i)+ord(j))+'_' # 加密字符 = 字符的Unicode码 + 秘钥的Unicode码
|
||
encry_str = encry_str + temp
|
||
return encry_str
|
||
|
||
|
||
# 解密
|
||
def dectry(p):
|
||
k = 'ez9z3a4m*$%srn9ve_t71yd!v+&xn9@0k(e(+l6#g1h=e5i4da'
|
||
dec_str = ""
|
||
for i, j in zip(p.split("_")[:-1], k):
|
||
# i 为加密字符,j为秘钥字符
|
||
# 解密字符 = (加密Unicode码字符 - 秘钥字符的Unicode码)的单字节字符
|
||
temp = chr(int(i) - ord(j))
|
||
dec_str = dec_str+temp
|
||
return dec_str
|
||
|
||
|
||
class QuestioncatViewSet(ModelViewSet):
|
||
perms_map = {'*': '*'}
|
||
queryset = Questioncat.objects.all()
|
||
serializer_class = QuestioncatSerializer
|
||
filterset_fields = ['parent']
|
||
search_fields = ['name']
|
||
|
||
|
||
class QuestionViewSet(ModelViewSet):
|
||
perms_map = {'*': '*'}
|
||
queryset = Question.objects.all()
|
||
serializer_class = QuestionSerializer
|
||
filterset_fields = ['level', 'type', 'year']
|
||
search_fields = ['name', 'options', 'resolution']
|
||
|
||
@action(methods=['get'], detail=False,
|
||
url_path='export', url_name='export_question', perms_map=[{'get': '*'}])
|
||
def export_question(self, request):
|
||
queryset = self.filter_queryset(self.get_queryset())
|
||
path = export_question(queryset)
|
||
return Response({'path': path})
|
||
|
||
@action(methods=['post'], detail=False, url_name='enable_question', permission_classes=[IsAuthenticated])
|
||
def enable(self, request):
|
||
ids = request.data.get('ids', None)
|
||
if ids:
|
||
Question.objects.filter(pk__in=ids).update(enabled=True)
|
||
return Response(status=200)
|
||
|
||
@action(methods=['post'], detail=False,
|
||
url_path='import', url_name='import_question', perms_map=[{'post': '*'}])
|
||
def import_question(self, request):
|
||
"""
|
||
导入题目
|
||
"""
|
||
xlsxpath = request.data['path']
|
||
fullpath = settings.BASE_DIR + xlsxpath
|
||
wb = load_workbook(fullpath)
|
||
sheet = wb.worksheets[0]
|
||
qlist = ['A', 'B', 'C', 'D', 'E', 'F']
|
||
leveldict = {'低': '低', '中': '中', '高': '高'}
|
||
notinlist = []
|
||
# 验证文件内容
|
||
if sheet['a2'].value != '题目类型':
|
||
return Response({"error": "类型列错误!"})
|
||
if sheet['b2'].value != '分类':
|
||
return Response({"error": "分类列错误!"})
|
||
if sheet['c2'].value != '题目':
|
||
return Response({"error": "题目列错误!"})
|
||
questioncatdict = {}
|
||
questioncats = Questioncat.objects.all()
|
||
for i in questioncats:
|
||
questioncatdict[i.name] = i.id
|
||
i = 3
|
||
while sheet['c'+str(i)].value:
|
||
type = sheet['a'+str(i)].value.replace(' ', '')
|
||
questioncat = sheet['b'+str(i)].value
|
||
if questioncat:
|
||
questioncat = questioncat.replace(' ', '')
|
||
else:
|
||
return Response(str(i)+'行没有分类', status=400)
|
||
name = sheet['c'+str(i)].value
|
||
|
||
answer = {}
|
||
if sheet['d'+str(i)].value:
|
||
answer['A'] = sheet['d'+str(i)].value
|
||
if sheet['e'+str(i)].value:
|
||
answer['B'] = sheet['e'+str(i)].value
|
||
if sheet['f'+str(i)].value:
|
||
answer['C'] = sheet['f'+str(i)].value
|
||
if sheet['g'+str(i)].value:
|
||
answer['D'] = sheet['g'+str(i)].value
|
||
if sheet['h'+str(i)].value:
|
||
answer['E'] = sheet['h'+str(i)].value
|
||
if sheet['i'+str(i)].value:
|
||
answer['F'] = sheet['i'+str(i)].value
|
||
right = sheet['j'+str(i)].value
|
||
if right:
|
||
right = right.replace(' ', '')
|
||
else:
|
||
return Response(str(i)+'行没有答案', status=400)
|
||
resolution = sheet['k'+str(i)].value
|
||
level = sheet['l'+str(i)].value
|
||
year = sheet['m' + str(i)].value
|
||
if level:
|
||
level = level.replace(' ', '')
|
||
cateobj = None
|
||
if questioncat not in questioncatdict:
|
||
return Response(str(i)+"行不存在分类("+questioncat+")!请先新建", status=400)
|
||
else:
|
||
cateobj = Questioncat.objects.get(
|
||
id=questioncatdict[questioncat])
|
||
if type == '单选':
|
||
if Question.objects.filter(type='单选', name=name, year=year, options=answer, questioncat=cateobj).exists():
|
||
notinlist.append(i)
|
||
else:
|
||
if right in ['A', 'B', 'C', 'D', 'E', 'F']:
|
||
obj = Question()
|
||
obj.type = '单选'
|
||
if cateobj:
|
||
obj.questioncat = cateobj
|
||
obj.name = name
|
||
obj.options = answer
|
||
obj.right = right
|
||
obj.resolution = resolution if resolution else ''
|
||
obj.year = year if year else None
|
||
if level in leveldict:
|
||
obj.level = leveldict[level]
|
||
else:
|
||
obj.level = '低'
|
||
obj.save()
|
||
elif type == '多选':
|
||
right = list(right.strip())
|
||
if Question.objects.filter(type='多选', name=name, year=year, options=answer, questioncat=cateobj).exists():
|
||
notinlist.append(i)
|
||
else:
|
||
if [False for c in right if c not in qlist]:
|
||
pass
|
||
else:
|
||
obj = Question()
|
||
obj.type = '多选'
|
||
obj.questioncat = cateobj
|
||
obj.name = name
|
||
obj.options = answer
|
||
obj.right = right
|
||
obj.resolution = resolution if resolution else ''
|
||
obj.year = year if year else None
|
||
if level in leveldict:
|
||
obj.level = leveldict[level]
|
||
else:
|
||
obj.level = '低'
|
||
obj.save()
|
||
elif type == '判断':
|
||
if right == 'A' or right == '对' or right == '正确':
|
||
right = 'A'
|
||
else:
|
||
right = 'B'
|
||
if Question.objects.filter(type='判断', name=name, is_delete=0, options={'A': '对', 'B': '错'}, questioncat=cateobj).exists():
|
||
notinlist.append(i)
|
||
else:
|
||
obj = Question()
|
||
obj.type = '判断'
|
||
obj.questioncat = cateobj
|
||
obj.name = name
|
||
obj.options = {'A': '对', 'B': '错'}
|
||
obj.right = right
|
||
obj.resolution = resolution if resolution else ''
|
||
obj.year = year if year else None
|
||
if level in leveldict:
|
||
obj.level = leveldict[level]
|
||
else:
|
||
obj.level = '低'
|
||
obj.save()
|
||
i = i + 1
|
||
return Response(notinlist, status=200)
|
||
|
||
|
||
class PaperViewSet(ModelViewSet):
|
||
"""
|
||
试卷增删改查
|
||
"""
|
||
perms_map = {'*': '*'}
|
||
queryset = Paper.objects.all()
|
||
serializer_class = PaperSerializer
|
||
ordering = ['id']
|
||
search_fields = ('name',)
|
||
|
||
def get_serializer_class(self):
|
||
if self.action in ['retrieve']:
|
||
return PaperDetailSerializer
|
||
elif self.action in ['create', 'update']:
|
||
return PaperCreateUpdateSerializer
|
||
return PaperSerializer
|
||
|
||
def create(self, request, *args, **kwargs):
|
||
sr = PaperCreateUpdateSerializer(data=request.data)
|
||
sr.is_valid(raise_exception=True)
|
||
vdata = sr.validated_data
|
||
questions_ = vdata.pop('questions_')
|
||
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))
|
||
PaperQuestion.objects.bulk_create(q_list)
|
||
return Response(status=201)
|
||
|
||
def update(self, request, *args, **kwargs):
|
||
return super().update(request, *args, **kwargs)
|
||
|
||
|
||
class ExamViewSet(ModelViewSet):
|
||
perms_map = {'*': '*'}
|
||
queryset = Exam.objects.all()
|
||
ordering = ['-id']
|
||
search_fields = ('name',)
|
||
|
||
def get_serializer_class(self):
|
||
if self.action in ['create', 'update']:
|
||
return ExamCreateUpdateSerializer
|
||
return ExamListSerializer
|
||
|
||
def destroy(self, request, *args, **kwargs):
|
||
instance = self.get_object()
|
||
if ExamRecord.objects.filter(exam=instance).exists():
|
||
raise ParseError('存在考试记录,禁止删除')
|
||
instance.delete()
|
||
return Response(status=204)
|
||
|
||
@action(methods=['post'], detail=False, perms_map=[{'post': '*'}], serializer_class=ExamAttendSerializer)
|
||
def attend(self, request, *args, **kwargs):
|
||
"""
|
||
参加考试
|
||
|
||
参加考试
|
||
"""
|
||
sr = ExamAttendSerializer(data=request.data)
|
||
sr.is_valid(raise_exception=True)
|
||
vdata = sr.validated_data
|
||
code = vdata['code']
|
||
now = timezone.now()
|
||
exam = Exam.objects.filter(
|
||
code=code, open_time__lt=now, close_time__gt=now).first()
|
||
if exam:
|
||
tests = ExamRecord.objects.filter(
|
||
exam=exam, create_by=request.user)
|
||
if tests.count() < exam.chance: # 还有考试机会就可以接着考
|
||
return Response(ExamListSerializer(instance=exam).data)
|
||
raise ParseError('考试机会已用完')
|
||
raise ParseError('有效考试不存在')
|