如何统计Django多对多关系中包含指定值的条目,解决标注计数异常问题
问题原因
- 跨多对多字段
annotated做关联查询时,Django ORM会自动执行JOIN操作,单个Image关联多个用户/多个生物标记物时会生成多条重复的Image记录,导致计数重复 Count函数未开启去重,重复行被多次统计,最终总计数超过实际图像数量- 额外遗漏:你代码中获取了
project查询参数,但未用其过滤Image集合,若业务要求按项目统计也会导致计数不符合预期
修复方案
方案1:修改现有查询逻辑
def get_queryset(self): user_object = self.request.user project_id = self.request.query_params.get('project', None) if project_id is None: raise Http404 # 若需要按项目过滤,补充对应过滤条件,示例:Image.objects.filter(project_id=project_id) queryset = Image.objects.all() queryset = queryset.annotate( annotations=Case( When(annotated=user_object, then=Value(1)), default=Value(0), output_field=IntegerField() ) ).distinct() # 先去重,排除多对多JOIN带来的重复Image行 return queryset.values('annotations').annotate( count=Count('id', distinct=True) # 按Image主键去重计数 ).order_by('annotations').values('count', 'annotations')
方案2:更简洁的实现(推荐)
你需要返回的是统计结果而非Image列表,直接用APIView实现更直观,无需复杂的分组查询:
from rest_framework.views import APIView from rest_framework.response import Response from django.http import Http404 class AnnotStatsView(APIView): def get(self, request): project_id = request.query_params.get('project') if not project_id: raise Http404 # 按项目过滤所有图像,根据实际业务调整过滤条件 all_images = Image.objects.filter(project_id=project_id) total_count = all_images.count() # 统计当前用户已标注的图像数量 annotated_count = all_images.filter(annotated=request.user).count() # 待标注数量直接计算即可 pending_count = total_count - annotated_count return Response({ "annotated_count": annotated_count, "pending_count": pending_count })
内容的提问来源于stack exchange,提问作者scandav
相关产品推荐
相关产品推荐

