views.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. # coding=utf-8
  2. import json
  3. import traceback
  4. from django.db.models import Sum, F
  5. from rest_framework.decorators import action
  6. from rest_framework.views import APIView
  7. from django.db import transaction
  8. from rest_framework.viewsets import ReadOnlyModelViewSet
  9. from django.db.models import Q
  10. from utils.custom_modelviewset import CustomModelViewSet
  11. from utils import response_ok, response_error
  12. from utils.permission import IsAdministrator
  13. from utils.format import ExcelImporter
  14. from apps.examination.examquestion.serializers import *
  15. from apps.examination.examquestion.filters import *
  16. from apps.system.models import SysLog
  17. from apps.foundation.models import Subject, Chapter
  18. class ExamQuestionViewSet(CustomModelViewSet):
  19. permission_classes = [IsAdministrator, ]
  20. queryset = ExamQuestion.objects.filter(delete=False)
  21. serializer_class = ExamQuestionSerializer
  22. def filter_queryset(self, queryset):
  23. queryset = queryset.filter()
  24. f = ExamQuestionFilter(self.request.GET, queryset=queryset)
  25. return f.qs
  26. def perform_create(self, serializer):
  27. super(ExamQuestionViewSet, self).perform_create(serializer)
  28. instance = serializer.instance
  29. validated_data = serializer.validated_data
  30. SysLog.objects.addnew(self.request.user, SysLog.INSERT, u'添加试题库试题,id=%d' % (instance.id), validated_data)
  31. def perform_update(self, serializer):
  32. super(ExamQuestionViewSet, self).perform_update(serializer)
  33. instance = serializer.instance
  34. validated_data = serializer.validated_data
  35. SysLog.objects.addnew(self.request.user, SysLog.UPDATE, u'修改试题库试题,id=%d' % (instance.id), validated_data)
  36. if 'feedback' in self.request.data and self.request.data['feedback']:
  37. feedback = ExamQuestionFeedback.getById(self.request.data['feedback'])
  38. feedback.process(self.request.user)
  39. feedback.save()
  40. SysLog.objects.addnew(self.request.user, SysLog.UPDATE, u'处理试题错误反馈,id=%d' % (feedback.id))
  41. def destroy(self, request, *args, **kwargs):
  42. with transaction.atomic():
  43. instance = self.get_object()
  44. instance.delete = True
  45. instance.save()
  46. SysLog.objects.addnew(request.user, SysLog.INSERT, u"删除试题库试题,id=%d" % instance.id)
  47. return response_ok()
  48. @action(methods=['post'], detail=False)
  49. def import_single(self, request):
  50. file = request.FILES.get('excel_file')
  51. status = ExcelImporter.validity(file)
  52. if not status['success']:
  53. return response_error(status['errors'])
  54. data = status['data']
  55. question_count = 0
  56. line = 2
  57. try:
  58. with transaction.atomic():
  59. cur_question = None
  60. for row in data:
  61. title = row['试题内容']
  62. subject = row['科目']
  63. chapter = row['章节']
  64. difficulty_text = row['难度']
  65. scores= row['分数']
  66. analysis = row['解析']
  67. content = row['选项']
  68. right = row['正确答案']
  69. if title and content:
  70. raise CustomError(u'第%d行:数据格式不正确' % line)
  71. if title and not content:
  72. if not subject:
  73. raise CustomError(u'第%d行:科目不能为空' % line)
  74. if not chapter:
  75. raise CustomError(u'第%d行:章节不能为空' % line)
  76. if not difficulty_text:
  77. raise CustomError(u'第%d行:难度不能为空' % line)
  78. if not scores:
  79. raise CustomError(u'第%d行:分数不能为空' % line)
  80. if difficulty_text == u'简单':
  81. difficulty = ExamQuestion.SIMPLE
  82. elif difficulty_text == u'中等':
  83. difficulty = ExamQuestion.MID
  84. elif difficulty_text == u'困难':
  85. difficulty = ExamQuestion.HARD
  86. else:
  87. raise CustomError(u'第%d行:难度为无效数据' % line)
  88. subject = Subject.objects.filter(name=subject, delete=False).first()
  89. if not subject:
  90. raise CustomError(u'第%d行:科目为无效数据' % line)
  91. chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
  92. if not chapter:
  93. raise CustomError(u'第%d行:章节为无效数据' % line)
  94. try:
  95. scores = int(scores)
  96. except:
  97. raise CustomError(u'第%d行:分数为无效数据' % line)
  98. cur_question = ExamQuestion.objects.create(
  99. chapter=chapter,
  100. type=ExamQuestion.SINGLE,
  101. difficulty=difficulty,
  102. scores=scores,
  103. title=title,
  104. analysis=analysis,
  105. create_user=request.user,
  106. create_time=timezone.now()
  107. )
  108. question_count += 1
  109. if content and not title:
  110. if not cur_question:
  111. continue
  112. if right:
  113. ExamQuestionOption.objects.create(main=cur_question, content=content, right=True)
  114. else:
  115. ExamQuestionOption.objects.create(main=cur_question, content=content)
  116. line += 1
  117. SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道单选题" % (question_count))
  118. except CustomError as e:
  119. return response_error(e.get_error_msg())
  120. except Exception as e:
  121. traceback.print_exc()
  122. return response_error(str(e))
  123. return response_ok()
  124. @action(methods=['post'], detail=False)
  125. def import_multiple(self, request):
  126. file = request.FILES.get('excel_file')
  127. status = ExcelImporter.validity(file)
  128. if not status['success']:
  129. return response_error(status['errors'])
  130. data = status['data']
  131. question_count = 0
  132. line = 2
  133. try:
  134. with transaction.atomic():
  135. cur_question = None
  136. for row in data:
  137. title = row['试题内容']
  138. subject = row['科目']
  139. chapter = row['章节']
  140. difficulty_text = row['难度']
  141. scores = row['分数']
  142. analysis = row['解析']
  143. content = row['选项']
  144. right = row['正确答案']
  145. if title and content:
  146. raise CustomError(u'第%d行:数据格式不正确' % line)
  147. if title and not content:
  148. if not subject:
  149. raise CustomError(u'第%d行:科目不能为空' % line)
  150. if not chapter:
  151. raise CustomError(u'第%d行:章节不能为空' % line)
  152. if not difficulty_text:
  153. raise CustomError(u'第%d行:难度不能为空' % line)
  154. if not scores:
  155. raise CustomError(u'第%d行:分数不能为空' % line)
  156. if difficulty_text == u'简单':
  157. difficulty = ExamQuestion.SIMPLE
  158. elif difficulty_text == u'中等':
  159. difficulty = ExamQuestion.MID
  160. elif difficulty_text == u'困难':
  161. difficulty = ExamQuestion.HARD
  162. else:
  163. raise CustomError(u'第%d行:难度为无效数据' % line)
  164. subject = Subject.objects.filter(name=subject, delete=False).first()
  165. if not subject:
  166. raise CustomError(u'第%d行:科目为无效数据' % line)
  167. chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
  168. if not chapter:
  169. raise CustomError(u'第%d行:章节为无效数据' % line)
  170. try:
  171. scores = int(scores)
  172. except:
  173. raise CustomError(u'第%d行:分数为无效数据' % line)
  174. cur_question = ExamQuestion.objects.create(
  175. chapter=chapter,
  176. type=ExamQuestion.MULTIPLE,
  177. difficulty=difficulty,
  178. scores=scores,
  179. title=title,
  180. analysis=analysis,
  181. create_user=request.user,
  182. create_time=timezone.now()
  183. )
  184. question_count += 1
  185. if content and not title:
  186. if not cur_question:
  187. continue
  188. if right:
  189. ExamQuestionOption.objects.create(main=cur_question, content=content, right=True)
  190. else:
  191. ExamQuestionOption.objects.create(main=cur_question, content=content)
  192. line += 1
  193. SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道多选题" % (question_count))
  194. except CustomError as e:
  195. return response_error(e.get_error_msg())
  196. except Exception as e:
  197. traceback.print_exc()
  198. return response_error(str(e))
  199. return response_ok()
  200. @action(methods=['post'], detail=False)
  201. def import_fill(self, request):
  202. file = request.FILES.get('excel_file')
  203. status = ExcelImporter.validity(file)
  204. if not status['success']:
  205. return response_error(status['errors'])
  206. data = status['data']
  207. question_count = 0
  208. line = 2
  209. try:
  210. with transaction.atomic():
  211. cur_question = None
  212. order = 0
  213. for row in data:
  214. title = row['试题内容']
  215. subject = row['科目']
  216. chapter = row['章节']
  217. difficulty_text = row['难度']
  218. scores = row['分数']
  219. analysis = row['解析']
  220. content = row['答案']
  221. if title and not content:
  222. raise CustomError(u'第%d行:答案不能为空' % line)
  223. if title and content:
  224. if not subject:
  225. raise CustomError(u'第%d行:科目不能为空' % line)
  226. if not chapter:
  227. raise CustomError(u'第%d行:章节不能为空' % line)
  228. if not difficulty_text:
  229. raise CustomError(u'第%d行:难度不能为空' % line)
  230. if not scores:
  231. raise CustomError(u'第%d行:分数不能为空' % line)
  232. if difficulty_text == u'简单':
  233. difficulty = ExamQuestion.SIMPLE
  234. elif difficulty_text == u'中等':
  235. difficulty = ExamQuestion.MID
  236. elif difficulty_text == u'困难':
  237. difficulty = ExamQuestion.HARD
  238. else:
  239. raise CustomError(u'第%d行:难度为无效数据' % line)
  240. subject = Subject.objects.filter(name=subject, delete=False).first()
  241. if not subject:
  242. raise CustomError(u'第%d行:科目为无效数据' % line)
  243. chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
  244. if not chapter:
  245. raise CustomError(u'第%d行:章节为无效数据' % line)
  246. try:
  247. scores = int(scores)
  248. except:
  249. raise CustomError(u'第%d行:分数为无效数据' % line)
  250. order = 1
  251. cur_question = ExamQuestion.objects.create(
  252. chapter=chapter,
  253. type=ExamQuestion.FILL,
  254. difficulty=difficulty,
  255. scores=scores,
  256. title=title,
  257. analysis=analysis,
  258. create_user=request.user,
  259. create_time=timezone.now()
  260. )
  261. ExamQuestionFill.objects.create(main=cur_question, content=content, order=order)
  262. question_count += 1
  263. order += 1
  264. if content and not title:
  265. if (not cur_question) or (not order):
  266. continue
  267. ExamQuestionFill.objects.create(main=cur_question, content=content, order=order)
  268. order += 1
  269. line += 1
  270. SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道填空题" % (question_count))
  271. except CustomError as e:
  272. return response_error(e.get_error_msg())
  273. except Exception as e:
  274. traceback.print_exc()
  275. return response_error(str(e))
  276. return response_ok()
  277. @action(methods=['post'], detail=False)
  278. def import_judgment(self, request):
  279. file = request.FILES.get('excel_file')
  280. status = ExcelImporter.validity(file)
  281. if not status['success']:
  282. return response_error(status['errors'])
  283. data = status['data']
  284. line = 2
  285. try:
  286. with transaction.atomic():
  287. for row in data:
  288. title = row['试题内容']
  289. subject = row['科目']
  290. chapter = row['章节']
  291. difficulty_text = row['难度']
  292. scores = row['分数']
  293. analysis = row['解析']
  294. judgment_text = row['答案']
  295. if not title:
  296. raise CustomError(u'第%d行:试题内容不能为空' % line)
  297. if not subject:
  298. raise CustomError(u'第%d行:科目不能为空' % line)
  299. if not chapter:
  300. raise CustomError(u'第%d行:章节不能为空' % line)
  301. if not difficulty_text:
  302. raise CustomError(u'第%d行:难度不能为空' % line)
  303. if not scores:
  304. raise CustomError(u'第%d行:分数不能为空' % line)
  305. if not judgment_text:
  306. raise CustomError(u'第%d行:答案不能为空' % line)
  307. if difficulty_text == u'简单':
  308. difficulty = ExamQuestion.SIMPLE
  309. elif difficulty_text == u'中等':
  310. difficulty = ExamQuestion.MID
  311. elif difficulty_text == u'困难':
  312. difficulty = ExamQuestion.HARD
  313. else:
  314. raise CustomError(u'第%d行:难度为无效数据' % line)
  315. if judgment_text == u'正确':
  316. judgment = True
  317. elif judgment_text == u'错误':
  318. judgment = False
  319. else:
  320. raise CustomError(u'第%d行:答案为无效数据' % line)
  321. subject = Subject.objects.filter(name=subject, delete=False).first()
  322. if not subject:
  323. raise CustomError(u'第%d行:科目为无效数据' % line)
  324. chapter = Chapter.objects.filter(subject=subject, name=chapter, delete=False).first()
  325. if not chapter:
  326. raise CustomError(u'第%d行:章节为无效数据' % line)
  327. try:
  328. scores = int(scores)
  329. except:
  330. raise CustomError(u'第%d行:分数为无效数据' % line)
  331. ExamQuestion.objects.create(
  332. chapter=chapter,
  333. type=ExamQuestion.JUDGMENT,
  334. difficulty=difficulty,
  335. scores=scores,
  336. title=title,
  337. judgment=judgment,
  338. analysis=analysis,
  339. create_user=request.user,
  340. create_time=timezone.now()
  341. )
  342. line += 1
  343. SysLog.objects.addnew(request.user, SysLog.IMPORT, u"导入[%d]道判断题" % (line - 2))
  344. except CustomError as e:
  345. return response_error(e.get_error_msg())
  346. except Exception as e:
  347. traceback.print_exc()
  348. return response_error(str(e))
  349. return response_ok()
  350. class ExamQuestionFeedbackViewSet(ReadOnlyModelViewSet):
  351. permission_classes = [IsAdministrator, ]
  352. queryset = ExamQuestionFeedback.objects.filter().order_by('status', '-id')
  353. serializer_class = ExamQuestionFeedbackSerializer
  354. def filter_queryset(self, queryset):
  355. f = ExamQuestionFeedbackFilter(self.request.GET, queryset=queryset)
  356. return f.qs