Django:共同关注者数量统计与模板展示实现,及实例查询类型错误求助
看起来你碰到了两个实打实的问题:一是模板里死活拿不到共同关注者的数量,二是查询Post模型时出现了实例类型不匹配的报错。我来一步步帮你捋清楚,给你落地的解决办法。
一、先解决模板里共同关注者数量不显示的问题
你现在模板里写的{{ user_following.count }}完全是找错了对象——user_following是单个的Profile实例,而count()是QuerySet才有的方法,单个实例哪来的count属性?而且你当前的逻辑是循环每个共同关注者的时候去计数,这本身就逻辑颠倒了:你要的是当前遍历的用户和登录用户之间的共同关注者总数,不是单个关注者的计数。
最优方案:在视图里预计算数量(效率更高)
直接在视图层给每个用户的Profile实例提前算好共同关注者数量,模板里直接用就行,还能避免模板里嵌套循环查数据库的性能问题:
修改你的FollowingView视图代码:
from django.db.models import Count, Q from django.shortcuts import render def FollowingView(request): page_title = "Following" current_profile = request.user.profile # 先拿到当前用户所有关注者的ID集合,后面复用 current_following_ids = current_profile.following.values_list('pk', flat=True) # 所有排除当前用户的其他用户Profile profile_users = Profile.objects.exclude(user=request.user) # 给每个profile_users实例添加mutual_count属性:计算和当前用户的共同关注者数量 profile_users = profile_users.annotate( mutual_count=Count( 'following', filter=Q(following__pk__in=current_following_ids) ) ) # 当前用户的所有关注者(用来在模板里显示头像) mutual_followers = current_profile.following.all() context = { 'page_title': page_title, 'profile_users': profile_users, 'mutual_followers': mutual_followers, } return render(request, 'your_template.html', context)
然后修改模板代码,现在可以直接调用预计算好的数量,同时优化头像循环的逻辑:
{% for users in profile_users %} <p>{{ users.user.username }}</p> {# 循环显示共同关注者的头像 #} {% for mutual in mutual_followers %} {% if mutual in users.following.all %} <img src="{{ mutual.profile_pic.url }}" class="hover-followers-img"/> {% endif %} {% endfor %} {# 直接显示预计算的共同关注者数量 #} <span>共同关注者:{{ users.mutual_count }}</span> {% endfor %}
另外提个小错误:你之前模板里的{% users.user %}是语法错了,Django模板输出变量要用双大括号{{ 变量 }},不是单大括号加百分号。
二、解决"Cannot query 'David': Must be 'Profile' instance."错误
这个错误的本质是:你在查询Post的时候,把User实例(比如David这个用户对象)当成了Profile实例来做过滤匹配,类型不匹配自然报错。我们先理清楚你的模型关系,再修正查询逻辑:
你的Post模型里,poster_profile是关联到AUTH_USER_MODEL的外键,而Profile和User是一对一关系。你之前的查询里有几处关系引用错误:
- Prefetch的目标错了:你要预取的是发帖用户的Profile的共同关注者,但你写的是
Prefetch('poster_profile', ...),poster_profile是User实例,不是Profile。 - OuterRef引用错了:
poster_profile__profile__to_profile_id=OuterRef('pk')里的OuterRef('pk')指向的是Post的ID,而to_profile_id需要的是Profile的ID,完全不搭。
修正后的Post查询逻辑
假设你要实现的是:筛选出发帖用户的关注者包含当前用户的Post,同时统计这些发帖用户和当前用户的共同关注者数量,还要预取共同关注者的Profile:
from django.db.models import Exists, OuterRef, Greatest, Count, Q from django.db.models import Prefetch def your_post_view(request): current_profile = request.user.profile current_following_ids = current_profile.following.values_list('pk', flat=True) # 子查询:判断某个Profile是否和当前用户有共同关注 mutual_subquery = Profile.objects.filter( pk=OuterRef('poster_profile__profile__pk'), following__pk__in=current_following_ids ) posts = Post.objects.filter( # 筛选发帖用户的Profile的关注者里有当前用户的Post Q(poster_profile__profile__followers__pk=current_profile.pk) ).annotate( # 计算共同关注者数量,用Greatest避免出现负数 mutual_count=Greatest( Count( 'poster_profile__profile__following', filter=Q(poster_profile__profile__following__pk__in=current_following_ids) ), 0 ), # 标记是否存在共同关注 has_mutual=Exists(mutual_subquery) ).prefetch_related( # 预取发帖用户的Profile的共同关注者,存到mutual_friends属性里 Prefetch( 'poster_profile__profile__following', queryset=Profile.objects.filter(pk__in=current_following_ids), to_attr='mutual_friends' ) ).order_by('?')
额外的避坑建议
给User和Profile加个自动创建的信号,确保每个新用户注册时都会自动生成对应的Profile实例,避免出现User没有Profile的情况:
from django.db.models.signals import post_save from django.dispatch import receiver from django.conf import settings @receiver(post_save, sender=settings.AUTH_USER_MODEL) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(user=instance) @receiver(post_save, sender=settings.AUTH_USER_MODEL) def save_user_profile(sender, instance, **kwargs): instance.profile.save()
内容来源于stack exchange

