如何避免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
相关产品推荐
相关产品推荐

