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

Django:无需循环高效获取每个分类下6个产品的方法

嘿,这个问题我之前也碰到过,原来的循环写法确实会触发太多数据库查询,尤其是分类多的时候效率很低。给你两个高效的方案,都不用显式循环,而且能大幅减少查询次数:

首先先贴一下你的模型和原来的实现,方便对照:

你的模型代码

class Category(models.Model):
    name = models.CharField(max_length=120, blank=True, null=True, default=None)

class Product(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)  # 实际项目里别忘了加on_delete参数

原来的实现

products = [Product.objects.filter(category_id=i.id)[:6] for i in Category.objects.all()]

方案一:用Prefetch对象(推荐,最简洁)

Django的Prefetch可以让我们自定义预取关联数据的逻辑,包括限制数量。这样只需要两次查询(一次查分类,一次查所有符合条件的产品),Django会自动把产品关联到对应的分类上:

from django.db.models import Prefetch

# 定义预取规则:每个分类只取前6个产品,存到top_products属性里
prefetch_top_products = Prefetch(
    'product_set',  # 这里是Category到Product的反向关联名,默认是`小写模型名_set`,如果加了related_name就用那个
    queryset=Product.objects.order_by('-created_at')[:6],  # 可以按你需要的字段排序,比如最新创建的在前
    to_attr='top_products'
)

# 一次性获取所有分类和对应的前6个产品
categories = Category.objects.prefetch_related(prefetch_top_products).all()

# 之后使用的时候,直接访问每个分类的top_products属性就行
for category in categories:
    print(f"分类{category.name}的前6个产品:{category.top_products}")

这个方法的好处是代码简洁,而且Django会帮你处理好关联,不需要手动映射,查询次数最少。

方案二:用Subquery子查询

如果你需要更灵活的控制,可以用Subquery来在Category的查询中直接获取每个分类的产品ID列表,之后再一次性查询产品实例:

from django.db.models import Subquery, OuterRef

# 定义子查询:获取每个分类下的前6个产品ID
top_product_ids = Product.objects.filter(
    category=OuterRef('pk')
).order_by('id')[:6].values_list('pk', flat=True)

# 查询所有分类,并附带各自的前6个产品ID
categories = Category.objects.annotate(
    top_product_ids=Subquery(top_product_ids)
).all()

# 一次性获取所有相关产品,避免多次查询
all_product_ids = []
for cat in categories:
    all_product_ids.extend(cat.top_product_ids)
products_map = {p.pk: p for p in Product.objects.filter(pk__in=all_product_ids)}

# 把产品实例映射到分类上
for cat in categories:
    cat.top_products = [products_map[pk] for pk in cat.top_product_ids]

这个方法适合需要对产品ID做额外处理的场景,总共3次查询,还是比原来的N+1高效很多。


总结一下,这两种方法都避免了显式循环查询,大幅减少了数据库交互次数,尤其是分类数量多的时候,性能提升会非常明显。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:09:47