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

Django QuerySet两层关联注解:按关联书籍阅读量排序Person列表

按关联书籍阅读次数排序Person列表的解决方案

嘿,这个需求其实挺常见的,核心就是要把Person→PersonBookRole→Book→Reading这条关联链打通,然后统计每个Person对应的总阅读次数就行。先给你理清楚步骤,再上代码:

先明确模型关联逻辑

假设你的模型结构大概是这样的(方便对应代码理解):

class Person(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    # 用through模型关联Person,记录角色
    people = models.ManyToManyField(Person, through='PersonBookRole')

class PersonBookRole(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    role = models.CharField(max_length=50)  # 比如"Author"、"Editor"

class Reading(models.Model):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    # 其他阅读字段,比如阅读时间、读者ID等

基础查询:统计所有关联书籍的总阅读次数

要实现按阅读次数排序,我们可以用Django的annotate结合Count来做,关键是要正确跨表关联:

from django.db.models import Count

# 获取按关联书籍总阅读次数降序排列的Person列表
sorted_people = Person.objects.annotate(
    # 链式关联:Person→PersonBookRole→Book→Reading,统计唯一的Reading记录数
    total_readings=Count('personbookrole__book__reading', distinct=True)
).order_by('-total_readings')

为什么加distinct=True?

因为一个Person可能和同一本书有多个角色(比如既是作者又是编辑),如果不加distinct,同一本书的阅读记录会被重复统计。加上之后就能确保每一条Reading只被计算一次。

进阶:按特定角色统计阅读次数

如果只想统计某类角色(比如只算作者关联的书籍阅读次数),可以先筛选角色再做统计:

from django.db.models import Count

# 只统计作为"Author"的Person,按其书籍阅读次数排序
author_sorted_people = Person.objects.filter(
    personbookrole__role='Author'
).annotate(
    total_author_readings=Count('personbookrole__book__reading', distinct=True)
).order_by('-total_author_readings')

额外技巧:排除无阅读记录的Person

如果不想展示那些没有任何书籍被阅读过的Person,可以在查询末尾加上过滤条件:

sorted_people = Person.objects.annotate(
    total_readings=Count('personbookrole__book__reading', distinct=True)
).filter(total_readings__gt=0).order_by('-total_readings')

这样就能得到完全符合你需求的排序结果啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:50:27