Django中get_queryset循环因GUID过滤产生重复SQL查询的解决办法
解决Django get_queryset中重复SQL查询的问题
你的问题出在循环内重复执行数据库查询:每次调用all_sections.filter(GUID=budget.SectionGUID)都会触发一次新的SQL查询——因为Django的QuerySet是惰性求值的,每次循环都会访问数据库。哪怕你提前获取了all_sections = CleanSections.objects.all(),filter操作会生成新的QuerySet,依然会发起重复请求。
优化方案:提前构建GUID到对象的映射字典
一次性从数据库取出所有CleanSections数据,存入以GUID为键的字典中,循环时直接通过GUID取值,全程只执行1次SQL查询。
修改后的代码如下:
def get_queryset(self): session = requests_cache.CachedSession('budget_cache', backend=backend, stale_if_error=True, expire_after=360) url = config('API') + 'BUDGET' response = session.get(url, auth=UNICA_AUTH) # 补上API响应解析逻辑(原代码遗漏了这一步) try: response_json = response.json() except ValueError: print('JSON解析失败') return [] queryset = [] # 提前构建GUID到CleanSection对象的映射字典,仅执行1次SQL查询 section_map = {section.GUID: section for section in CleanSections.objects.all()} for item in response_json: parsed_json = ReportProjectBudgetSerializer.parse_raw(json.dumps(item)) if parsed_json.ObjectGUID != select_front: continue for budget in parsed_json.BudgetData: # 直接从内存字典取对应对象,无需再查数据库 budget.SectionGUID = section_map.get(budget.SectionGUID) budget.СompletedContract = budget.СompletedContract * 100 budget.СompletedEstimate = budget.СompletedEstimate * 100 queryset.append(budget) return queryset
关键优化点说明
section_map = {section.GUID: section for section in CleanSections.objects.all()}:一次性拉取所有CleanSections数据,生成键为GUID的字典,仅触发1次SQL查询。- 循环内用
section_map.get(budget.SectionGUID)替代filter:直接从内存字典取值,完全避免重复数据库请求。 - 简化了原代码的条件判断逻辑,去掉冗余的
obj赋值,让代码更简洁。
另外提个小问题:原代码里response_json初始化为None,但没有对API响应做解析,实际运行时else分支永远不会执行,修改后的代码已补上这部分处理。
内容的提问来源于stack exchange,提问作者Zesshi
相关产品推荐
相关产品推荐

