Django中使用prefetch_related时如何指定模型管理器避免多余查询?
解决Django预取关联时继承自定义管理器查询的问题
你可以通过以下几种方式避免预取关联时继承Product自定义管理器的额外查询:
1. 用Prefetch对象指定“裸”查询集
Django的Prefetch类允许你完全自定义预取时使用的查询集,直接清空自定义管理器中添加的select_related和prefetch_related即可:
from django.db.models import Prefetch # 在查询Offer时这样写 Offer.objects.prefetch_related( Prefetch( 'condition_products', # 清空所有预取和关联,只查询Product本身 queryset=Product.objects.all().select_related(None).prefetch_related(None) ) )
select_related(None)会移除自定义管理器中设置的select_related,prefetch_related(None)会清除所有预取关联,得到一个仅查询Product基础字段的“裸”查询集。
2. 给Product添加专门的“裸”管理器
在Product模型里定义一个不包含任何额外关联的基础管理器,方便复用:
from django.db import models class BasicProductManager(models.Manager): def get_queryset(self): # 仅返回默认的查询集,不添加任何关联或预取 return super().get_queryset() class Product(models.Model): # 你的字段定义... objects = ProductManager() # 原自定义管理器 basic_objects = BasicProductManager() # 裸管理器
之后预取时直接使用这个裸管理器的查询集:
Offer.objects.prefetch_related( Prefetch( 'condition_products', queryset=Product.basic_objects.all() ) )
3. 让自定义管理器支持动态控制关联
修改你的ProductManager,添加参数控制是否启用额外关联,兼顾日常使用和裸查询的需求:
class ProductManager(models.Manager): def get_queryset(self, with_related=True): qs = super().get_queryset() if with_related: qs = qs.select_related("core_product").prefetch_related(...) return qs # 快捷方法,直接返回裸查询集 def bare(self): return self.get_queryset(with_related=False)
预取时调用这个快捷方法即可:
Offer.objects.prefetch_related( Prefetch( 'condition_products', queryset=Product.objects.bare() ) )
内容的提问来源于stack exchange,提问作者Kevin Renskers
相关产品推荐
相关产品推荐

