You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何统计Django多对多关系中包含指定值的条目,解决标注计数异常问题

问题原因

  1. 跨多对多字段annotated做关联查询时,Django ORM会自动执行JOIN操作,单个Image关联多个用户/多个生物标记物时会生成多条重复的Image记录,导致计数重复
  2. Count函数未开启去重,重复行被多次统计,最终总计数超过实际图像数量
  3. 额外遗漏:你代码中获取了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 06:24:02