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

Django如何判断登录用户是否已点赞多对多关联的图片

问题

开发了一个艺术画廊Web应用,以网格形式展示图片,每张图片上显示点赞用户数,已通过AJAX实现动态点赞/取消点赞及实时增减计数功能。现在需要实现:页面加载时,若当前登录用户未点赞某张图片,该图片的点赞按钮显示黑色;若已点赞,则显示蓝色(类似Facebook或Instagram的效果)。

现有代码

Portrait模型(省略部分字段):

class Portrait(models.Model):
    likes = models.ManyToManyField(User, related_name='like', default=None, blank=True)
    like_count = models.BigIntegerField(default=0)

views.py中的index视图:

def index(request):
    paintingObjects = Portrait.objects.all()
    context = {
        'paintingObjects': paintingObjects,
    }
    return render(request, "index.html", context)

希望在index.html模板中实现类似如下逻辑(伪代码):

{% for paintingData in paintingObjects %}
    {% if request.user.is_authenticated %}
        {% if 当前登录用户在paintingData的'likes'字段中 %}
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:blue"></i>
            </span>
        </a>
        {% else 用户尚未点赞该paintingData %}
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:black"></i>
            </span>
        </a>
    {% endif %}
{% endfor %}

请问如何访问Portrait模型的"likes"字段中的用户列表,并判断当前登录用户是否在其中?

解决方案

方法一:模板直接判断(简单但需注意性能)

在Django模板中可直接用in运算符判断当前用户是否在paintingData.likes关联列表里,修改模板代码如下:

{% for paintingData in paintingObjects %}
    {% if request.user.is_authenticated %}
        {% if request.user in paintingData.likes.all %}
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:blue"></i>
            </span>
        </a>
        {% else %}
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:black"></i>
            </span>
        </a>
        {% endif %}
    {% else %}
        <!-- 未登录用户显示灰色按钮 -->
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:gray"></i>
            </span>
        </a>
    {% endif %}
{% endfor %}

注意:这种写法会触发N+1查询问题——每遍历一张图片就会额外执行一次查询获取点赞用户列表,图片数量多时会拖慢页面加载速度,建议用下面的优化方案。

方法二:预加载关联数据(优化性能)

在视图中用prefetch_related提前加载所有图片的点赞用户,减少数据库查询次数:
修改views.py的index视图:

def index(request):
    # 预加载likes关联数据,避免N+1查询
    paintingObjects = Portrait.objects.all().prefetch_related('likes')
    context = {
        'paintingObjects': paintingObjects,
    }
    return render(request, "index.html", context)

模板代码和方法一完全一致,但此时所有图片的点赞用户已在一次查询中获取完毕,不会产生额外数据库请求,性能更优。

方法三:用annotate标记点赞状态(最优性能)

通过annotate结合Exists子查询,直接在数据库查询阶段给每个Portrait对象添加user_liked字段,标记当前用户是否点赞:
修改views.py:

from django.db.models import Exists, OuterRef

def index(request):
    if request.user.is_authenticated:
        # 给每个Portrait添加user_liked字段,判断当前用户是否点赞
        paintingObjects = Portrait.objects.annotate(
            user_liked=Exists(
                request.user.like.filter(pk=OuterRef('pk'))
            )
        )
    else:
        paintingObjects = Portrait.objects.all()
    
    context = {
        'paintingObjects': paintingObjects,
    }
    return render(request, "index.html", context)

模板中直接判断user_liked字段即可,代码更简洁:

{% for paintingData in paintingObjects %}
    {% if request.user.is_authenticated %}
        {% if paintingData.user_liked %}
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:blue"></i>
            </span>
        </a>
        {% else %}
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:black"></i>
            </span>
        </a>
        {% endif %}
    {% else %}
        <a role="button" class="like-click" id="{{paintingData.id}}">
            <span style="float: left;" class="p-1 mt-1">
                <i class="fa fa-thumbs-up" style="font-size:22px;color:gray"></i>
            </span>
        </a>
    {% endif %}
{% endfor %}

这种方法性能最优,仅需一次数据库查询就能完成所有判断逻辑,无额外查询开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 07:10:29