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

Django模型:对非直接关联模型执行聚合操作

针对非直接关联模型的聚合操作方案

嘿,针对你给出的UserProfile和UserRating这两个非直接关联的模型,我整理了几个基于Django ORM的聚合实现方案,完全不用写原生SQL就能搞定需求~

核心思路

这两个模型虽然没有直接外键关联,但都和User模型绑定:UserProfile是一对一关联,UserRating是双向外键关联。所以我们可以把User作为中间桥梁,通过ORM的关联查询语法把它们串起来,再结合聚合函数完成统计。

场景1:获取每个用户的Profile信息 + 他们的平均被评分

比如你想统计每个用户的个人资料,同时算出他们收到的所有评分的平均值,可以这么写:

from django.db.models import Avg
from django.db.models.functions import Coalesce

# 关联User模型,同时聚合平均评分,用Coalesce处理无评分的情况(返回0而非None)
profiles_with_avg_rating = UserProfile.objects.select_related('user').annotate(
    avg_rating=Coalesce(Avg('user__rated_user__rating'), 0)
)

# 遍历结果示例
for profile in profiles_with_avg_rating:
    print(f"用户名: {profile.user.username}")
    print(f"个人字段: {profile.some_field}")
    print(f"平均被评分: {profile.avg_rating}\n")

这里的关键是user__rated_user__rating路径:

  • user是UserProfile关联的User实例
  • rated_user是UserRating中subject_user的related_name,指向所有给这个用户的评分记录
  • 最后对rating字段取平均值,用Coalesce避免无评分时返回None

场景2:统计每个评分者的Profile + 他们给出的评分总数/平均分

如果你想从评分者的角度统计,比如看每个用户(带Profile)一共给别人打了多少次分,或者他们给出的评分的平均值:

from django.db.models import Count, Avg

# 方案1:从UserProfile出发聚合
raters_profile_stats = UserProfile.objects.select_related('user').annotate(
    total_given_ratings=Count('user__rating_user__id'),
    avg_given_rating=Avg('user__rating_user__rating')
)

# 方案2:从UserRating出发聚合,再关联Profile
rating_stats = UserRating.objects.values(
    'rating_user__id', 'rating_user__userprofile__some_field'
).annotate(
    total_ratings=Count('id'),
    avg_rating=Avg('rating')
).order_by('-total_ratings')

解释下路径:

  • user__rating_user是User模型通过UserRating中rating_user的related_name,指向这个用户给出的所有评分记录
  • 用values指定要分组的字段(比如评分者ID和他们的Profile字段),再结合annotate做聚合统计

场景3:筛选特定Profile用户的评分数据

比如你想找出some_field等于某个值的用户,统计他们收到的评分分布:

from django.db.models import Count

# 先筛选Profile,再关联评分记录并按评分值分组统计
target_profile_ratings = UserProfile.objects.filter(some_field="目标值").select_related('user').annotate(
    rating_distribution=Count('user__rated_user__rating', distinct=True)
).values('user__rated_user__rating', 'rating_distribution')

注意事项

  • 你的UserRating模型已经设置了unique_together = ("subject_user", "rating_user"),确保了同一个用户不会给另一个用户重复评分,所以聚合时不会出现重复统计的问题,这点很赞~
  • 如果数据量较大,建议用select_related(一对一/外键)或prefetch_related(多对多/反向外键)来减少数据库查询次数,避免N+1问题

内容的提问来源于stack exchange,提问作者Bartosz Bąk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:39:58