serializers.py 10.6 KB
# coding=utf-8
import datetime

from gm_serializer import serializers
from gm_types.gaia import USER_TYPE
from gm_types.mimas.enum import MEDIA_IMAGE_URL_SOURCE, IMAGE_TYPE

from qa import validators
from qa.models import (
    Question,
    QuestionImage,
    QuestionTag,
    Answer,
    AnswerImage,
    AnswerReply,
    AnswerVote,
    AnswerVoteReply,
    AnswerTag,
    QuestionTagV3
)
from qa.tasks.view import gif_create_webp
from utils.rpc import get_current_user, RPCMixin, rpc_client
from qa.utils.image import img_type, handle_image_type


class QuestionImageSerializer(serializers.ModelSerializer):

    class Meta:
        model = QuestionImage
        fields = ('image_url', 'create_time', 'update_time', "width", "height", "image_url_source")


class QuestionTagSerializer(serializers.ModelSerializer):

    tag = serializers.MagicField()

    class Meta:
        lazy_fields = ('tag',)
        model = QuestionTag
        fields = ('id', 'tag',)


class QuestionSerializer(serializers.MagicSerializer):
    images = QuestionImageSerializer(many=True)
    tags = QuestionTagSerializer(many=True)
    user = serializers.MagicField(
        validators=[validators.BlacklistValidator()],
    )
    content = serializers.CharField(allow_blank=True, allow_null=True,
    )
    title = serializers.CharField()

    class Meta:
        model = Question
        lazy_fields = ('user',)
        fields = '__all__'

    def save_question_tag_v3(self, question, tags_data):
        """
        保存问题对应的新标签
        :param question: 问题对象
        :param tags_data: 老标签数据 [{'tag': 11, }]
        :return:
        """
        # 获取老标签对应的新标签
        old_tag_ids = [old_tag['tag'] for old_tag in tags_data]
        try:
            old_map_new_data_dict = rpc_client['api/tag_v3/get_map_new_tag_by_old_ids'](old_tag_ids=old_tag_ids).unwrap()
        except:
            old_map_new_data_dict = {}

        question_tag_v3_obj_list = list()
        for _, tag_v3_info_list in old_map_new_data_dict.items():
            for tag_v3_info in tag_v3_info_list:
                question_tag_v3_obj_list.append(
                    QuestionTagV3(
                        question_id=question.id,
                        tag_v3_id=tag_v3_info['id']
                    )
                )
        i = 0
        bulk_count = 500
        while i < len(question_tag_v3_obj_list):
            QuestionTagV3.objects.bulk_create(question_tag_v3_obj_list[i : i + bulk_count])
            i += bulk_count

    def create(self, validated_data):
        """
        question create
        :param validated_data:
        :return:
        """
        images_data = validated_data.pop('images')
        tags_data = validated_data.pop('tags')
        question = Question.objects.create(**validated_data)

        image_urls = [image_data['image_url'] for image_data in images_data if image_data['image_url']]
        gevent_dic = handle_image_type(image_urls)
        gif_create_webp.delay(conent_id=question.id, content_type="question")

        image_list = list()
        for image_data in images_data:

            if image_data["image_url"]:
                question_image = QuestionImage(
                    question=question,
                    image_url=image_data['image_url'],
                    width=image_data.get("width", 0),
                    height=image_data.get("height", 0),
                    image_url_source=image_data.get("image_url_source", MEDIA_IMAGE_URL_SOURCE.CREATE),
                    image_type=gevent_dic.get(image_data['image_url'], IMAGE_TYPE.OTHER) or IMAGE_TYPE.OTHER,
                )
                image_list.append(question_image)

        if image_list:
            QuestionImage.objects.bulk_create(image_list)

        for tag in tags_data:
            try:
                QuestionTag(question=question, tag=tag['tag']).save()
            except serializers.ValidationError:
                pass

        # 保存问题对应的新标签关系
        self.save_question_tag_v3(question, tags_data)

        return question


class AnswerTagSerializer(serializers.ModelSerializer):

    tag = serializers.MagicField()

    class Meta:
        lazy_fields = ('tag',)
        model = AnswerTag
        fields = ('id', 'tag',)


class AnswerSerializer(serializers.MagicSerializer):
    images = QuestionImageSerializer(many=True)
    tags = AnswerTagSerializer(many=True)
    user = serializers.MagicField(
        validators=[validators.BlacklistValidator()]
    )
    content = serializers.CharField()

    class Meta:
        model = Answer
        lazy_fields = ('user',)
        fields = '__all__'

    def create(self, validated_data):
        images_data = validated_data.pop('images')
        tags_data = validated_data.pop('tags')
        answer = Answer.objects.create(**validated_data)

        image_urls = [image_data['image_url'] for image_data in images_data if image_data['image_url']]
        gevent_dic = handle_image_type(image_urls)
        gif_create_webp.delay(conent_id=answer.id, content_type='answer')

        image_list = []
        for image_data in images_data:
            if image_data["image_url"]:
                t = AnswerImage(
                    answer=answer,
                    image_url=image_data['image_url'],
                    width=image_data.get("width", 0),
                    height=image_data.get("height", 0),
                    image_url_source=image_data.get("image_url_source", MEDIA_IMAGE_URL_SOURCE.CREATE),
                    image_type=gevent_dic.get(image_data['image_url'], IMAGE_TYPE.OTHER) or IMAGE_TYPE.OTHER,
                )
                image_list.append(t)
        if image_list:
            AnswerImage.objects.bulk_create(image_list)

        answer_tag_list = list()
        for tag in tags_data:
            answer_tag_list.append(AnswerTag(answer=answer, tag=tag['tag']))
        if answer_tag_list:
            AnswerTag.objects.bulk_create(answer_tag_list)

        return answer


class AnswerReplySerializer(serializers.MagicSerializer):
    answer = serializers.PrimaryKeyRelatedField(queryset=Answer.objects.all())
    commented_reply = serializers.PrimaryKeyRelatedField(queryset=AnswerReply.objects.all(), allow_null=True)
    user = serializers.MagicField(
        validators=[validators.BlacklistValidator()]
    )
    content = serializers.CharField(
        validators=[validators.FilterWordValidator(), validators.RepeatedValidator(AnswerReply, 'content')]
    )

    class Meta:
        model = AnswerReply
        lazy_fields = ('user',)
        fields = '__all__'

    def create(self, validated_data):
        comment_reply = validated_data.pop('commented_reply')

        answer_reply = AnswerReply(**validated_data)

        if comment_reply:                                        #二级评论 评论给评论
            reply = AnswerReply.objects.get(pk=comment_reply.id)
            if reply.first_reply:
                answer_reply.first_reply_id = reply.first_reply_id
            else:
                answer_reply.first_reply_id = comment_reply.id

            answer_reply.commented_reply_id = comment_reply.id

            # 自己评论自己 则至为已读状态
            if answer_reply.user_id == comment_reply.user_id:
                answer_reply.is_read = True

            answer_reply.save()
        else:                                                   #一级评论  评论给回答
            answer = validated_data.get("answer")
            if answer_reply.user_id == answer.user_id:
                answer_reply.is_read = True
            answer_reply.save()
        answer_reply.answer.save()
        return answer_reply


class AnswerVoteSerializer(serializers.MagicSerializer):
    answer = serializers.PrimaryKeyRelatedField(queryset=Answer.objects.all())

    class Meta:
        model = AnswerVote
        lazy_fields = ('user',)
        fields = '__all__'

    def create(self, validated_data):
        vote = AnswerVote.objects.create(**validated_data)
        vote.answer.like_num += 1
        vote.answer.save()
        return vote


class AnswerReplyVoteSerializer(serializers.MagicSerializer):
    user = serializers.MagicField()
    answerreply = serializers.PrimaryKeyRelatedField(queryset=AnswerReply.objects.all())

    class Meta:
        model = AnswerVoteReply
        lazy_fields = ('user',)
        fields = '__all__'

    def create(self, validated_data):
        vote = AnswerVoteReply.objects.create(**validated_data)
        vote.answerreply.like_num += 1
        vote.answerreply.save()
        return vote


class AnswerListSerializer(serializers.MagicSerializer):

    author = serializers.SerializerMethodField()
    comment_count = serializers.IntegerField(source="comment_num")
    is_voted = serializers.SerializerMethodField()
    user_type = serializers.SerializerMethodField()
    images = serializers.SerializerMethodField()
    create_time = serializers.SerializerMethodField()
    replies = serializers.SerializerMethodField()
    first_reply_count = serializers.IntegerField(source="first_reply_num")  # 新增返回一级评论数,用于加载更多

    def get_user_type(self, obj):
        return USER_TYPE.NORMAL

    def get_author(self, obj):
        return {
            'user_id': obj.user.id,
            'user_type': USER_TYPE.NORMAL,
            'user_name': obj.user.nickname,
            'user_portrait': obj.user.portrait,
            'membership_level': obj.user.membership_level,
            'user_level': {
                'membership_icon': obj.user.membership_icon,
                'level_icon': obj.user.level_icon,
                'constellation_icon': obj.user.constellation_icon,
            },
            "college_id": obj.user.get("college_id", 0),
            "college_name": obj.user.get("college_name", ""),
        }

    def get_is_voted(self, obj):
        user = get_current_user()
        if user:
            return AnswerVote.objects.filter(answer=obj, user=user.id).exists()
        return False

    def get_images(self, obj):
        return [image.image_url for image in obj.images.filter(image_url_source=MEDIA_IMAGE_URL_SOURCE.CREATE).all()]

    def get_create_time(self, obj):
        return obj.create_time.strftime('%y-%m-%d %H:%M')

    def get_replies(self, obj):
        replies = AnswerReply.objects.filter(answer=obj, first_reply__isnull=True, is_online=True).order_by("create_time")[:2]
        return [reply.get_data_for_reply(new_order=True) for reply in replies]

    class Meta:
        model = Answer
        lazy_fields = ('user',)
        fields = (
            'id', 'create_time', 'content', 'author', 'user_type', 'is_voted',
            'comment_count', 'like_num', 'images', 'platform', 'replies',
            'first_reply_count','is_recommend', 'video_cover_list',
        )