You need to enable JavaScript to run this app. Django 中如何获取按分类分组、含关联文章列表的结构化queryset
优惠活动
大模型
产品
解决方案
定价
更多

Django 中如何获取按分类分组、含关联文章列表的结构化queryset

按分类维度聚合关联文章的Django ORM实现

前置模型修正

现有模型存在两处容易触发运行错误的小问题,实现查询前建议先调整:

  • person模型里关联Interest的外键拼写为Ineterest,属于笔误,需修正为Interest
  • 两个ManyToManyField字段的default=None配置不符合Django字段规则:多对多字段不支持设置默认值,保留该参数会在服务启动时报错,建议直接移除该参数

核心实现方案(无N+1查询,性能最优)

利用prefetch_related预取关联数据,总共仅需2次数据库查询即可拿到全量匹配结果,避免循环内逐分类查库的性能损耗:

from django.db import models
from your_app.models import Interest, Article

# 1. 预取每个Interest分类下关联的所有Article
interest_list = Interest.objects.prefetch_related(
    models.Prefetch(
        # Article模型category字段的反向默认关联名
        'article_set',
        # 此处可追加文章的过滤条件,比如仅拉取已发布的文章
        queryset=Article.objects.all(),
        # 将预取的结果绑定到指定属性,避免和默认反向管理器混淆
        to_attr='related_articles'
    )
).all()

# 2. 组装成目标结构格式
target_result = []
for interest in interest_list:
    target_result.append({
        # 分类名取Interest模型中interest字段的存储值,比如'Finance'
        'category': interest.interest,
        # 转成列表存放对应分类下的所有文章对象
        'articles': list(interest.related_articles)
    })

常用场景适配调整

  • 过滤空分类:如果不需要展示没有关联任何文章的分类,可在初始查询链上追加注解过滤:
    interest_list = Interest.objects.annotate(
        article_total=models.Count('article_set')
    ).filter(
        article_total__gt=0
    ).prefetch_related(...) # 后续预取逻辑和上面保持一致
    
  • 文章排序需求:如果需要每个分类下的文章按发布时间/热度排序,直接在Prefetch的queryset参数里追加排序规则即可,比如queryset=Article.objects.order_by('-publish_time')
  • 精简文章返回内容:如果不需要完整的Article对象,只需要存文章ID/标题,可在组装结构时直接取对应字段值,无需将整个模型对象塞入列表。

注意:不推荐在循环内逐次调用interest.article_set.all()的写法,这种写法会触发N+1次数据库查询,当分类规模较大时会带来明显的数据库压力。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.14 09:15:09