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__"