You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Django序列化器中get方法多次执行?

问题原因分析

你的问题核心在于序列化器的关联关系逻辑错误:

  • TagSerializer对应Article和Tag的多对多关联,many=True会把该文章所有关联的Tag对象序列化为一个列表,这符合预期。
  • 但SentimentSerializer绑定的是Reaction模型,而Article和Reaction是一对多关系(一篇文章对应多个Reaction),当你在ArticleSerializer里设置article_sentiment = SentimentSerializer(many=True, read_only=True)时,DRF会遍历这篇文章的每一个Reaction对象,分别调用一次get_sentiment方法,所以会生成多个sentiment列表,同时导致get_sentiment被多次调用。

而你的get_sentiment方法本质是统计整个文章的点赞/点踩数据,不需要针对单个Reaction对象处理,这种嵌套方式完全不匹配需求。

修复方案

方案一:直接在ArticleSerializer中实现统计(推荐)

去掉单独的SentimentSerializer,用SerializerMethodField直接在ArticleSerializer里处理情感统计,代码修改如下:

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('tag',)
        model = Tag

class ArticleSerializer(serializers.ModelSerializer):
    article_tags = TagSerializer(many=True, read_only=True)
    # 替换原有的SentimentSerializer嵌套,用SerializerMethodField直接处理
    article_sentiment = serializers.SerializerMethodField()

    class Meta:
        fields = (
            'id',
            'title',
            'content',
            'article_tags',
            'pub_date',
            'preview_image',
            'author',
            'author_profile_name',
            'article_sentiment',
        )
        model = Article

    def get_article_sentiment(self, obj):
        # obj是当前Article对象,直接基于它统计
        likes = Reaction.objects.filter(article=obj, sentiment=1).count()
        dislikes = Reaction.objects.filter(article=obj, sentiment=2).count()
        if likes + dislikes == 0:
            return 0
        percent = (likes / (likes + dislikes)) * 100
        print(f"{obj.title} {percent}")
        return [likes, dislikes, percent]

方案二:保留SentimentSerializer,修改作用对象

如果一定要保留SentimentSerializer,可以修改它的处理对象为Article(而非Reaction):

class SentimentSerializer(serializers.Serializer):
    sentiment = serializers.SerializerMethodField()

    class Meta:
        fields = ('sentiment',)
        # 无需绑定Reaction模型,改为处理Article对象

    def get_sentiment(self, obj):
        # 此时obj是Article对象
        likes = Reaction.objects.filter(article=obj, sentiment=1).count()
        dislikes = Reaction.objects.filter(article=obj, sentiment=2).count()
        if likes + dislikes == 0:
            return 0
        percent = (likes / (likes + dislikes)) * 100
        print(f"{obj.title} {percent}")
        return [likes, dislikes, percent]

class ArticleSerializer(serializers.ModelSerializer):
    article_tags = TagSerializer(many=True, read_only=True)
    # 去掉many=True,每个Article只对应一组情感统计
    article_sentiment = SentimentSerializer(read_only=True)

    class Meta:
        fields = (
            'id',
            'title',
            'content',
            'article_tags',
            'pub_date',
            'preview_image',
            'author',
            'author_profile_name',
            'article_sentiment',
        )
        model = Article
效果说明

修改后,article_sentiment会生成单个列表,包含该文章的总点赞数、总点踩数和点赞百分比,同时统计方法只会被调用一次,解决了多次调用和多列表的问题。

内容的提问来源于stack exchange,提问作者user14611431

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 02:10:32