Django中defer()与only()查询集未生效问题及正确用法咨询
问题分析与解决方案
看起来你对Django的only()/defer()用法存在一点误解,同时也遇到了外键关联数据加载的常见问题,我来一步步帮你理清:
一、为什么only()/defer()看起来和all()结果一致,甚至更慢?
首先要明确:only()和defer()不会改变QuerySet返回的是模型实例这个事实,它们只是控制Django首次查询数据库时加载哪些字段。
你遇到的问题根源在于:
- 当你用
only('xxx')后,模板代码里大概率访问了不在指定列表中的字段——这时候Django会触发懒加载:为每个Donor对象单独发一次SQL查询去获取缺失的字段,也就是经典的N+1查询问题(1次查所有Donor,2000次查每个Donor的缺失字段),所以耗时反而比all()更长。 - 对于
jamatkhana这个外键字段,only('jamatkhana')只会加载外键的ID值,当你在模板里访问donor.jamatkhana.name这类关联对象的字段时,同样会触发额外的SQL查询,进一步拖慢速度。
二、正确获取指定字段(含外键关联数据)的方法
根据你的需求,分两种场景给出解决方案:
场景1:需要返回模型实例(保持模板代码的调用习惯)
如果你希望继续用模型实例(比如模板里还是用donor.jamatkhana.name这种写法),需要结合only() + select_related()来预加载关联对象,同时明确指定需要的关联字段:
def donor(request): donors = Donors.objects.only( # 指定Donor模型本身需要的字段 'donorid','donor_type','title','donor_name','address', 'mobile_no', # 指定外键关联对象需要的字段(双下划线语法) 'jamatkhana__name', 'jamatkhana__location' # 替换成你实际需要的jamatkhana字段 ).select_related('jamatkhana') # 预加载jamatkhana关联对象,避免N+1查询 return render(request,"hod_template/add_donor_template.html",{"donors":donors})
⚠️ 注意:模板里只能访问only()列表中明确指定的字段(包括关联对象的字段),如果访问了不在列表中的字段,还是会触发懒加载,回到之前的慢查询问题。
场景2:不需要模型实例,只需要字典格式的数据
如果可以接受返回字典(模板里调整为字典的访问方式),用values()结合双下划线语法就能直接获取外键关联数据:
def donor(request): donors = Donors.objects.values( 'donorid','donor_type','title','donor_name','address', 'mobile_no', # 直接指定外键关联字段 'jamatkhana__name', 'jamatkhana__code' ) return render(request,"hod_template/add_donor_template.html",{"donors":donors})
此时模板里需要用{{ donor.jamatkhana__name }}这种方式访问关联字段的值,而不是{{ donor.jamatkhana.name }}。
三、关于defer()的补充说明
defer()是only()的反向操作——它指定不需要加载的字段,用法和注意事项和only()完全一致:必须配合select_related()处理外键,且不能访问被defer的字段,否则会触发懒加载。
比如你如果想排除某些大字段(比如文本字段),可以这样写:
donors = Donors.objects.defer('description', 'remark').select_related('jamatkhana')
内容的提问来源于stack exchange,提问作者manasiya sumail
相关产品推荐
相关产品推荐

