如何在Django中按ID分组获取首个非空组织字段的QuerySet
解决Django QuerySet按ID获取首个非空Organisation的问题
没问题,我来帮你搞定这个需求!你想要的是按id分组,每个id保留第一个非空的organisation值,如果某个id对应的所有organisation都是空的,就保留None。这里有几种实用的实现方式,你可以根据数据量和场景选择:
方法一:数据库层面处理(推荐,效率更高)
直接用Django ORM的聚合函数和条件判断,在数据库层面完成筛选,适合数据量大的场景:
from django.db.models import Case, When, Value, F from django.db import models # 替换成你的实际模型类名 result = YourModel.objects.annotate( # 给每条记录标记非空的organisation,空的则设为None non_empty_org=Case( When(organisation__isnull=False, then=F('organisation')), default=Value(None), output_field=models.CharField() # 这里要匹配你的organisation字段类型,比如models.TextField() ) ).order_by('id', '-non_empty_org').distinct('id')
逻辑说明:
annotate给每条记录添加一个临时字段non_empty_org,非空的organisation会保留原值,空的则为None;order_by('id', '-non_empty_org')先按id分组排序,同时把有非空organisation的记录排在同id的最前面;distinct('id')会保留每个id的第一条记录,也就是优先拿到非空的organisation,如果没有则保留None。
方法二:拆分QuerySet合并
如果觉得上面的写法有点复杂,可以分两步筛选再合并:
# 第一步:获取所有存在非空organisation的id对应的第一条记录 non_empty_records = YourModel.objects.filter(organisation__isnull=False).distinct('id') # 第二步:获取那些所有organisation都是空的id对应的记录 null_only_ids = YourModel.objects.values_list('id', flat=True).exclude( id__in=non_empty_records.values_list('id', flat=True) ) null_only_records = YourModel.objects.filter(id__in=null_only_ids).distinct('id') # 合并两个QuerySet result = non_empty_records | null_only_records
方法三:Python层面处理(适合小数据量)
如果你的数据量不大,也可以在Python内存中处理,逻辑更直观:
from collections import OrderedDict # 获取原始QuerySet queryset = YourModel.objects.all() # 用OrderedDict来保证顺序,同时去重 unique_entries = OrderedDict() for item in queryset: if item.id not in unique_entries: # 第一次遇到这个id,直接存入 unique_entries[item.id] = item else: # 如果之前存入的该id记录organisation是空的,现在这个非空,就替换 if unique_entries[item.id].organisation is None and item.organisation is not None: unique_entries[item.id] = item # 最终结果可以转成列表,或者再转回QuerySet final_result = list(unique_entries.values()) # 如果需要QuerySet格式: # final_result = YourModel.objects.filter(id__in=unique_entries.keys()).order_by('id')
小结
如果数据量较大,优先选方法一,因为数据库层面的处理比Python内存处理效率高很多;小数据量的话,方法三的逻辑更易懂,调试起来也方便。
内容的提问来源于stack exchange,提问作者rajukancharla
相关产品推荐
相关产品推荐

