Django Rest Framework中如何按Category分组QuerySet?
嘿,刚好处理过类似的需求,给你几个实用的方案,根据你的场景选就行:
方案1:用Django预加载+构建分组字典(推荐,避免N+1查询)
你的模型已经给Category设置了related_name='items',我们可以利用Django的Prefetch来一次性加载所有关联数据,避免频繁查询数据库,然后构建一个清晰的分组结构:
from django.db.models import Prefetch # 预加载所有分类及其关联的内容,也可以根据需求过滤分类(比如只查已发布的) categories = Category.objects.prefetch_related( Prefetch('items', queryset=Item.objects.all()) ).all() # 构建分组字典,key是Category对象(或标题),value是对应Item列表 grouped_items = {} # 先处理有分类的内容 for category in categories: # 这里可以用category.title作为key,方便后续展示 grouped_items[category.title] = list(category.items.all()) # 单独处理没有分类的内容(category为null的Item) uncategorized_items = Item.objects.filter(category__isnull=True).all() if uncategorized_items: grouped_items['未分类'] = list(uncategorized_items)
这个方案只需要2次数据库查询,性能最优,而且能拿到完整的Category和Item对象,方便后续业务逻辑处理。
方案2:Python层面用
itertools.groupby分组 如果你已经有了一批Item的QuerySet,想在内存里直接分组,可以用Python标准库的groupby,但要注意必须先按category排序,因为groupby只能对连续的相同键进行分组:
from itertools import groupby from operator import attrgetter # 先获取所有Item,按category字段排序(null值会被排到一起) items = Item.objects.all().order_by('category') # 按category属性分组,构建字典 grouped_items = {} for key, item_group in groupby(items, key=attrgetter('category')): # 处理无分类的情况,key为None时用自定义名称 category_name = key.title if key else '未分类' grouped_items[category_name] = list(item_group)
这个方案适合小数据量场景,如果Item数量很大,会把所有数据加载到内存,性能不如方案1。
方案3:用PostgreSQL的聚合函数(仅适用于PostgreSQL数据库)
如果你的项目用的是PostgreSQL,可以用ArrayAgg聚合函数直接在数据库层面完成分组,返回每个分类下的内容列表:
from django.contrib.postgres.aggregates import ArrayAgg from django.db.models import Value from django.db.models.functions import Coalesce # 按分类分组,直接聚合出每个分类下的Item标题列表 grouped_data = Item.objects.values( # 用Coalesce处理null的分类,替换为自定义名称 category_title=Coalesce('category__title', Value('未分类')) ).annotate( item_titles=ArrayAgg('title') ).order_by('category_title') # 转成字典格式 grouped_items = {item['category_title']: item['item_titles'] for item in grouped_data}
这个方案完全在数据库层面完成分组,效率很高,但只支持PostgreSQL,且返回的是字段列表而非完整对象。
内容的提问来源于stack exchange,提问作者penlightment
相关产品推荐
相关产品推荐

