193 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
| from apps.utils.serializers import CustomModelSerializer
 | |
| from rest_framework import serializers
 | |
| from .models import Questioncat, Question, Paper, PaperQuestion, Exam, ExamRecord, AnswerDetail, Train
 | |
| from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE
 | |
| from django.db import transaction
 | |
| from apps.utils.snowflake import idWorker
 | |
| 
 | |
| class QuestioncatSerializer(CustomModelSerializer):
 | |
|     class Meta:
 | |
|         model = Questioncat
 | |
|         fields = '__all__'
 | |
| 
 | |
| class QuestionSerializer(CustomModelSerializer):
 | |
|     questioncat_name = serializers.CharField(source="questioncat.name", read_only=True)
 | |
|     class Meta:
 | |
|         model = Question
 | |
|         fields = '__all__'
 | |
| 
 | |
| class PaperListSerializer(CustomModelSerializer):
 | |
|     class Meta:
 | |
|         model = Paper
 | |
|         exclude = ["questions"]
 | |
| 
 | |
| class PaperPatchSerializer(CustomModelSerializer):
 | |
|     class Meta:
 | |
|         model = Paper
 | |
|         fields = ["name"]
 | |
| 
 | |
| class PaperQuestionSerializer(CustomModelSerializer):
 | |
|     question_name = serializers.CharField(source="question.name", read_only=True)
 | |
|     question_type = serializers.CharField(source="question.type", read_only=True)
 | |
|     class Meta:
 | |
|         model = PaperQuestion
 | |
|         fields = '__all__'
 | |
|         read_only_fields = EXCLUDE_FIELDS_BASE + ["paper"]
 | |
| 
 | |
| class PaperSerializer(CustomModelSerializer):
 | |
|     detail = PaperQuestionSerializer(many=True)
 | |
|     class Meta:
 | |
|         model = Paper
 | |
|         exclude = ["questions"]
 | |
|         read_only_fields = EXCLUDE_FIELDS
 | |
|     
 | |
|     def create(self, validated_data):
 | |
|         detail = validated_data.pop("detail", [])
 | |
|         with transaction.atomic():
 | |
|             question_ids = [item["question"] for item in detail]
 | |
|             if len(question_ids) != len(set(question_ids)):
 | |
|                 raise serializers.ValidationError("存在重复的题目")
 | |
|             paper = Paper.objects.create(**validated_data)
 | |
|             qs = [PaperQuestion(id=idWorker.get_id(), paper=paper, question=item["question"], total_score=item["total_score"], sort=item["sort"]) for item in detail]
 | |
|             PaperQuestion.objects.bulk_create(qs)
 | |
|         return paper
 | |
|     
 | |
|     def update(self, instance, validated_data):
 | |
|         detail = validated_data.pop("detail", [])
 | |
|         with transaction.atomic():
 | |
|             paper = super().update(instance, validated_data)
 | |
|             # 删除未有的数据
 | |
|             question_ids = [item["question"] for item in detail]
 | |
|             if len(question_ids) != len(set(question_ids)):
 | |
|                 raise serializers.ValidationError("存在重复的题目")
 | |
|             PaperQuestion.objects.filter(paper=paper).exclude(question__id__in=question_ids).delete()
 | |
|             # 更新新数据
 | |
|             for item in detail:
 | |
|                 PaperQuestion.objects.update_or_create(
 | |
|                     paper=instance,
 | |
|                     question=item["question"],
 | |
|                     defaults={
 | |
|                         "total_score": item["total_score"],
 | |
|                         "sort": item["sort"]
 | |
|                     }
 | |
|                 )
 | |
|         return paper
 | |
|     
 | |
|     def to_representation(self, instance):
 | |
|         ret = super().to_representation(instance)
 | |
|         ret['detail'] = sorted(ret['detail'], key=lambda x: (x['sort'], x['create_time']))
 | |
|         return ret
 | |
| 
 | |
| class ExamSerializer(CustomModelSerializer):
 | |
|     create_by_name = serializers.CharField(source='create_by.name', read_only=True)
 | |
|     paper_name = serializers.CharField(source='paper.name', read_only=True)
 | |
|     paper_total_score = serializers.IntegerField(source='paper.total_score', read_only=True)
 | |
|     paper_pass_score = serializers.IntegerField(source='paper.pass_score', read_only=True)
 | |
|     paper_limit = serializers.IntegerField(source='paper.limit', read_only=True)
 | |
|     paper = serializers.PrimaryKeyRelatedField(queryset=Paper.objects.all(), label='有考试记录,编辑时忽略')
 | |
|     class Meta:
 | |
|         model = Exam
 | |
|         fields = "__all__"
 | |
|         read_only_fields = EXCLUDE_FIELDS
 | |
|     
 | |
|     def update(self, instance, validated_data):
 | |
|         if ExamRecord.objects.filter(exam=instance).exists():
 | |
|             validated_data.pop("paper", None)
 | |
|         return super().update(instance, validated_data)
 | |
| 
 | |
| class ExamDetailSerializer(CustomModelSerializer):
 | |
|     paper_ = PaperSerializer(source='paper')
 | |
| 
 | |
|     class Meta:
 | |
|         model = Exam
 | |
|         fields = "__all__"
 | |
|         read_only_fields = EXCLUDE_FIELDS
 | |
| 
 | |
| 
 | |
| 
 | |
| class AnswerDetailOutSerializer(CustomModelSerializer):
 | |
|     name = serializers.ReadOnlyField(source='question.name')
 | |
|     options = serializers.ReadOnlyField(source='question.options')
 | |
|     type = serializers.ReadOnlyField(source='question.type')
 | |
|     img = serializers.ReadOnlyField(source='question.img')
 | |
|     questioncat_name = serializers.ReadOnlyField(
 | |
|         source='question.questioncat.name')
 | |
|     level = serializers.ReadOnlyField(source='question.level')
 | |
| 
 | |
|     class Meta:
 | |
|         model = AnswerDetail
 | |
|         fields = ['id', 'question', 'name', 'options', 'type', 'level',
 | |
|                   'total_score', 'questioncat_name', 'img', 'user_answer', 'score', 'is_right']
 | |
| 
 | |
| 
 | |
| class AnswerDetailSerializer(AnswerDetailOutSerializer):
 | |
|     right = serializers.ReadOnlyField(source='question.right')
 | |
|     class Meta:
 | |
|         model = AnswerDetail
 | |
|         fields = ['id', 'question', 'name', 'options', 'type', 'level', 'right',
 | |
|                   'total_score', 'questioncat_name', 'img', 'user_answer', 'score', 'is_right']
 | |
| 
 | |
| class AnswerDetailUpdateSerializer(serializers.Serializer):
 | |
|     id = serializers.CharField(label='下发ID')
 | |
|     user_answer = serializers.JSONField(label='作答')
 | |
| 
 | |
| class ExamRecordInitSerizlier(CustomModelSerializer):
 | |
|     detail = serializers.SerializerMethodField()
 | |
| 
 | |
|     class Meta:
 | |
|         model = ExamRecord
 | |
|         fields = ["id", "detail"]
 | |
|     
 | |
|     def get_detail(self, obj):
 | |
|         objs = AnswerDetail.objects.select_related('question').filter(
 | |
|             examrecord=obj).order_by('id')
 | |
|         return AnswerDetailOutSerializer(instance=objs, many=True).data
 | |
| 
 | |
| 
 | |
| class TookSerializerMixin:
 | |
|     took_format = serializers.SerializerMethodField()
 | |
| 
 | |
|     def get_took_format(self, obj):
 | |
|         m, s = divmod(obj.took, 60)
 | |
|         h, m = divmod(m, 60)
 | |
|         return "%02d:%02d:%02d" % (h, m, s) 
 | |
| 
 | |
| class ExamRecordSerializer(CustomModelSerializer, TookSerializerMixin):
 | |
|     create_by_name = serializers.CharField(source='create_by.name', read_only=True)
 | |
|     exam_open_time = serializers.DateTimeField(source='exam.open_time', read_only=True)
 | |
|     exam_close_time = serializers.DateTimeField(source='exam.close_time', read_only=True)
 | |
|     total_score = serializers.IntegerField(source='exam.paper.total_score', read_only=True)
 | |
|     pass_score = serializers.IntegerField(source='exam.paper.pass_score', read_only=True)
 | |
|     exam_name = serializers.CharField(source='exam.name', read_only=True)
 | |
|     paper_name = serializers.CharField(source='exam.paper.name', read_only=True)
 | |
|     
 | |
|     class Meta:
 | |
|         model = ExamRecord 
 | |
|         exclude = ["questions"]
 | |
| 
 | |
| 
 | |
| class ExamRecordDetailSerializer(ExamRecordSerializer, TookSerializerMixin):
 | |
|     detail = serializers.SerializerMethodField()
 | |
|     
 | |
|     class Meta:
 | |
|         model = ExamRecord
 | |
|         fields = "__all__"
 | |
| 
 | |
|     def get_detail(self, obj):
 | |
|         objs = AnswerDetail.objects.select_related('question').filter(
 | |
|             examrecord=obj).order_by('id')
 | |
|         return AnswerDetailSerializer(instance=objs, many=True).data
 | |
| 
 | |
| class ExamRecordSubmitSerializer(serializers.ModelSerializer):
 | |
|     detail = AnswerDetailUpdateSerializer(many=True)
 | |
| 
 | |
|     class Meta:
 | |
|         model = ExamRecord
 | |
|         fields = ['detail']
 | |
| 
 | |
| class TrainingSerializer(CustomModelSerializer):
 | |
| 
 | |
|     class Meta:
 | |
|         model = Train
 | |
|         fields = "__all__"
 |