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

Django:比较两个QuerySet生成带好友标记的用户列表(避免模板嵌套循环)

解决Django中高效标记用户好友状态的方案

嘿,我完全懂你的痛点——在模板里嵌套循环比对两个QuerySet不仅写起来麻烦,还特别影响性能,尤其是用户多的时候。给你两个干净利落的解决方案,都能避免在模板里做这种低效操作:

方案一:数据库层面用annotate + Exists子查询(最优解)

这是性能最好的方式,直接让数据库帮我们完成好友关系的判断,一次查询搞定所有数据。

首先,假设你的Friends模型是类似这样的(如果结构不同,你只需要调整下面的过滤条件就行):

class Friends(models.Model):
    user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='sent_friendships')
    friend = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='received_friendships')
    status = models.CharField(max_length=20, default='pending')  # 比如有pending/accepted状态

在你的视图函数里,用annotate给每个UserProfile对象新增一个is_friend字段:

from django.db.models import Exists, OuterRef

def user_list_view(request):
    # 获取当前用户的UserProfile
    current_profile = request.user.userprofile
    
    # 标注每个用户是否是当前用户的已通过好友
    user_profiles = UserProfile.objects.annotate(
        is_friend=Exists(
            # 匹配当前用户发起的、对方已接受的好友关系
            Friends.objects.filter(
                user=current_profile,
                friend=OuterRef('pk'),
                status='accepted'
            ) | 
            # 匹配对方发起的、当前用户已接受的好友关系
            Friends.objects.filter(
                user=OuterRef('pk'),
                friend=current_profile,
                status='accepted'
            )
        )
    ).exclude(pk=current_profile.pk)  # 排除当前用户自己
    
    return render(request, 'user_list.html', {'user_profiles': user_profiles})

然后在模板里直接用这个字段就行,完全不用嵌套循环:

{% for profile in user_profiles %}
    <div class="user-card">
        <h3>{{ profile.user.username }}</h3>
        {% if profile.is_friend %}
            <span class="tag tag-success">已加好友</span>
        {% else %}
            <a href="{% url 'send_friend_request' profile.pk %}" class="btn btn-primary">添加好友</a>
        {% endif %}
    </div>
{% endfor %}

这个方案的优势:数据库层面一次性完成所有计算,没有Python层面的循环比对,性能拉满,模板代码也非常简洁。

方案二:视图层面预处理好友ID列表

如果暂时不想用子查询,也可以在视图里先把当前用户的所有好友ID提取出来,再给每个UserProfile手动添加is_friend属性:

def user_list_view(request):
    current_profile = request.user.userprofile
    
    # 获取所有已通过好友的ID列表
    # 这里根据你的Friends模型结构调整查询
    friend_ids = set(
        # 当前用户发起的已通过好友
        Friends.objects.filter(user=current_profile, status='accepted').values_list('friend__pk', flat=True)
        |
        # 对方发起的已通过好友
        Friends.objects.filter(friend=current_profile, status='accepted').values_list('user__pk', flat=True)
    )
    
    # 获取所有用户(排除自己)
    user_profiles = UserProfile.objects.exclude(pk=current_profile.pk)
    
    # 给每个用户添加is_friend属性
    for profile in user_profiles:
        profile.is_friend = profile.pk in friend_ids
    
    return render(request, 'user_list.html', {'user_profiles': user_profiles})

模板里的用法和方案一完全一样,这个方案比模板嵌套循环好太多,因为逻辑都在视图里处理,模板只负责展示,不过性能比方案一略逊一筹,适合对数据库查询不太熟悉的情况。

注意事项

  • 一定要根据你实际的Friends模型结构调整查询条件,比如如果你的好友关系是单向的、或者没有状态字段,就去掉对应的过滤条件。
  • 记得排除当前用户自己,避免在列表里显示自己的资料。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:47:42