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

Django DRF中如何判断当前登录用户是否已点赞问题?

问题:判断登录用户是否点赞问题时出现TypeError错误及解决方法

错误原因

你遇到的TypeError: 'RelatedManager' object is not iterable,是因为obj.feelings是Django的RelatedManager对象——它是管理关联数据的接口,并非直接可迭代的QuerySet集合。直接用for feeling in obj.feelings遍历会报错,必须调用.all()、.filter()等方法获取实际的QuerySet后才能进行遍历操作。

正确实现方式

下面提供几种高效的实现方案,避免重复查询数据库:

方案1:优化序列化器方法(直接检查存在性)

无需遍历所有点赞记录,直接通过filter+exists()判断,仅生成1条高效的查询语句:

def get_liked(self, obj):
    request = self.context.get('request')
    if request and request.user.is_authenticated:
        return obj.feelings.filter(user=request.user).exists()
    return False

方案2:视图层用annotate预注入字段(推荐,避免N+1查询)

如果是批量查询Question列表,用annotate在数据库层面直接计算是否点赞,彻底避免每条Question单独查询点赞记录的N+1性能问题:

视图层代码

from django.db.models import Exists, OuterRef
from rest_framework import viewsets

class QuestionViewSet(viewsets.ModelViewSet):
    queryset = Question.objects.all()
    serializer_class = QuestionSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        if self.request.user.is_authenticated:
            # 用OuterRef关联当前Question,Exists判断用户是否有点赞记录
            queryset = queryset.annotate(
                liked=Exists(
                    QuestionFeeling.objects.filter(
                        question=OuterRef('pk'),
                        user=self.request.user
                    )
                )
            )
        return queryset

序列化器代码

直接读取预注入的liked字段,无需额外查询:

from rest_framework import serializers

class QuestionSerializer(serializers.ModelSerializer):
    liked = serializers.BooleanField(read_only=True)
    # 如果需要返回点赞列表,添加嵌套序列化器
    feelings = QuestionFeelingSerializer(many=True, read_only=True)

    class Meta:
        model = Question
        fields = ['id', 'title', 'body', 'user', 'created_at', 'updated_at', 'feelings', 'liked']

方案3:修复原序列化器的遍历逻辑(不推荐,效率低)

如果一定要用遍历的方式,需要先调用.all()获取可迭代的QuerySet,但这种方式会加载所有点赞记录,数据量大时效率很低:

def get_liked(self, obj):
    request = self.context.get('request')
    if request and request.user.is_authenticated:
        logged_user_id = request.user.id
        # 先调用.all()获取可迭代的QuerySet
        for feeling in obj.feelings.all():
            if feeling.user_id == logged_user_id:
                return True
    return False

附相关代码

Question模型

class Question(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField(max_length=10000)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")

    class Meta:
        verbose_name = "question"
        verbose_name_plural = "questions"
        db_table = "questions"

    def __str__(self):
        return self.body

QuestionFeeling模型

class QuestionFeeling(models.Model):
    like = "like"
    feelings = [
        (like , "like"),
    ]
    feeling = models.CharField(max_length=15,choices=feelings, default=like)
    question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='feelings')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="question_feelings")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
    
    class Meta:
        unique_together = ['question', 'user']
        verbose_name = "Question feeling"
        verbose_name_plural = "Question feelings"
        db_table = "question_feeling"

    def __str__(self):
        return str(self.feeling)

前端返回的feelings结构

feelings: Array [ {…} ]
0: Object { id: 1, feeling: "like", created_at: "2023-02-13T04:21:43.323313Z", … }
created_at: "2023-02-13T04:21:43.323313Z"
feeling: "like"
id: 1
question: 14
updated_at: "2023-02-13T04:21:43.323358Z"
user: 33

报错的原序列化器方法

def get_liked(self, obj):
    request = self.context.get('request', None)
    if request:
        loggedUser = self.context["request"].user.id  
        for feeling in obj.feelings:
            if loggedUser == feeling.user:
                return True

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:45:14