如何在Django QuerySet中显示重复的Stock对象
问题描述
我有一个Stock模型,正尝试在数据库中查找重复项。当使用Stock.objects.filter(component__in=components)过滤时,期望显示所有重复对象,但该操作会自动排除重复项。比如我的components列表结构如下:
1 2 3 1(子组件,可转换为component对象) 2(子组件,可转换为component对象) 3(子组件,可转换为component对象) 4 5 6 ...
过滤后,第一个3下的1、2、3对象因ID相同被剔除,但我需要保留所有这些对象。
相关代码:
def get_custom_queryset(self): params = {} reference = False for param in iter(self.request.GET): if param.startswith('Search_'): search = param[7:] if search == 'inventory': try: inventory = self.request.GET[param] if inventory == 'on': components, stock_codes = [], [] stock = Stock.objects.filter(is_inventory=True) # 不能用first(),因为self.table需要queryset而非列表 for s in stock: stock_codes.append(s.component.code) components_on_inventory = Component.objects.filter(code__in=stock_codes) for coi in components_on_inventory: if coi.has_subcomponents(): qs_sc = [] components.append(coi) for sc in coi.subcomponents(): qs_sc.append(sc.subcomponent) components.append(qs_sc) else: components.append(coi) i = 0 while i < len(components): if isinstance(components[i], list): sc_list = components[i] components = components[:i] + sc_list + components[i+1:] i += 1 queryset = Stock.objects.filter(component__in=components) if queryset.filter(is_inventory=False).exists(): # 有时Stock QuerySet会自动出现非库存组件,所以要删除这些项 queryset.filter(is_inventory=False).delete() self.queryset = queryset reference = True break except: pass
解决方案
Django的__in查询会自动去重,因为数据库返回的是唯一行。要保留重复项,得换个方式处理:
收集包含重复ID的组件列表
先把components转换成包含重复ID的列表,确保所有重复项都被保留:component_ids = [comp.id for comp in components]循环查询每个ID对应的Stock对象,合并结果到列表
放弃用__in一次性查询,改为循环每个ID查询,把结果添加到列表中(列表不会自动去重):stock_list = [] for comp_id in component_ids: # 直接过滤is_inventory=True,省去后续删除步骤 stocks = Stock.objects.filter(component_id=comp_id, is_inventory=True) stock_list.extend(stocks)替换原代码中的查询逻辑
把原代码里的queryset = Stock.objects.filter(component__in=components)及后续删除操作,替换为上面的列表生成逻辑:# 替换原代码中从queryset = ...到self.queryset = queryset的部分 component_ids = [comp.id for comp in components] stock_list = [] for comp_id in component_ids: stocks = Stock.objects.filter(component_id=comp_id, is_inventory=True) stock_list.extend(stocks) # 如果表格接受列表作为数据源,直接赋值 self.queryset = stock_list优化子组件收集逻辑
原代码中展开子组件的循环可以简化,避免处理嵌套列表:# 替换原代码中收集components的循环 components = [] for coi in components_on_inventory: components.append(coi) if coi.has_subcomponents(): # 直接把所有子组件添加到列表中 components.extend([sc.subcomponent for sc in coi.subcomponents()])
注意:如果你的表格必须接收QuerySet作为数据源,那无法直接显示重复行(因为QuerySet是数据库层面的查询结果,天然去重),此时需要调整表格渲染逻辑,比如通过注解(
annotate)统计每个组件的出现次数,在表格中显示次数而非重复行。
内容的提问来源于stack exchange,提问作者Diego David Brescia Rosa diego
相关产品推荐
相关产品推荐

