Django搜索函数调用.defer()排除查询集unique_num字段不生效问题
问题原因
- 参数传入错误:
defer方法要求传入字符串格式的字段名,你代码中写的是defer(unique_num),没有给unique_num加引号,相当于传入了一个名为unique_num的变量,若该变量未定义会直接报错,即使变量存在值也很难匹配到模型的实际字段,导致defer规则完全不生效。 - 对
defer的作用存在误解:defer是查询优化手段,作用是执行SQL查询时不加载指定字段,将该字段的加载延迟到你主动访问它的时候,并不会把字段从模型实例中移除。所以当你打印实例、序列化实例时如果触发了该字段的访问,Django会自动发起额外的SQL查询拿到该字段的值,你自然就能看到这个字段。 - 后续处理逻辑触发了字段加载:你代码中把QuerySet拆分为单个模型实例,再通过
list(set(queryset))去重,这个过程中模型实例的哈希计算、比较操作都有可能触发延迟字段的加载,导致unique_num被查询出来。
解决方案
场景1:仅需要优化查询性能,不需要彻底移除字段
首先修正defer的参数格式,同时替换掉低效的循环追加+set去重逻辑,避免不必要的字段加载:
def get_client_queryset(query=None): if not query: return clients.objects.none() queryset = clients.objects.none() queries = query.split(' ') for q in queries: qs = clients.objects.filter( Q(name__icontains=q) | Q(number__icontains=q) | Q(email__icontains=q) ).distinct().defer("unique_num") queryset = queryset | qs return queryset.distinct()
修改后初始查询不会加载unique_num字段,只有主动访问该属性时才会发起额外查询。
场景2:需要返回结果中彻底不包含unique_num字段
如果是接口返回等场景,建议通过显式指定返回字段的方式从根源排除unique_num,不要直接返回模型实例:
- 用
values返回字典格式结果:
# 仅列出你需要返回的字段,不要加入unique_num details = clients.objects.filter( Q(name__icontains=q) | Q(number__icontains=q) | Q(email__icontains=q) ).distinct().values("id", "name", "number", "email")
- 如果使用DRF序列化器,直接在序列化器的
fields配置中移除unique_num即可。
内容的提问来源于stack exchange,提问作者Baked Potato
相关产品推荐
相关产品推荐

