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

Django中高效统计不同状态用户数量的最优实现方法

Django User模型多状态统计优化方案

问题描述

在Django项目中,需要统计User模型(角色为role=2)不同状态的用户数量。当前尝试通过多次annotate实现,但希望找到更简便的单次查询方案,避免多次调用count()产生多查询,同时优化现有写法。

当前实现代码:

workers = get_user_model().objects.annotate(
            not_active_workers=Count("id", filter=Q(is_active=False, status=0))
        ).annotate(
            active_not_complete_workers=Count("id", filter=Q(is_active=True, profile_completed=False, status=0))
        ).annotate(
            complete_applicant_workers=Count("id", filter=Q(is_active=True, profile_completed=True, status=0))
        ).annotate(
            former_workers=Count("id", filter=Q(is_active=False, status=2))
        ).annotate(
            accepted_workers=Count("id", filter=Q(is_active=False, status=1))
        ).filter(role=2)

dict(
  not_active=workers[0].not_active_workers,
  active_not_complete=workers[0].active_not_complete_workers,
  complete_applicant=workers[0].complete_applicant_workers,
  former=workers[0].former_workers,
  accepted=workers[0].accepted_workers, 
)

优化方案1:使用aggregate结合Count+filter(最简洁)

你的现有写法是可行的,但因为不需要分组统计(仅针对role=2的所有用户做全局统计),用aggregate替代annotate更贴合需求,无需取查询集第一个元素,直接返回统计结果字典:

from django.db.models import Count, Q
from django.contrib.auth import get_user_model

User = get_user_model()

stats = User.objects.filter(role=2).aggregate(
    not_active=Count("id", filter=Q(is_active=False, status=0)),
    active_not_complete=Count("id", filter=Q(is_active=True, profile_completed=False, status=0)),
    complete_applicant=Count("id", filter=Q(is_active=True, profile_completed=True, status=0)),
    former=Count("id", filter=Q(is_active=False, status=2)),
    accepted=Count("id", filter=Q(is_active=False, status=1))
)

# stats直接就是目标字典,示例输出:{'not_active': 5, 'active_not_complete': 12, ...}

优化方案2:使用Case+When+Sum

如果偏好更直观的条件判断逻辑,也可以用Case和When配合Sum实现,同样是单次查询:

from django.db.models import Case, When, IntegerField, Sum
from django.contrib.auth import get_user_model

User = get_user_model()

stats = User.objects.filter(role=2).aggregate(
    not_active=Sum(
        Case(
            When(is_active=False, status=0, then=1),
            default=0,
            output_field=IntegerField()
        )
    ),
    active_not_complete=Sum(
        Case(
            When(is_active=True, profile_completed=False, status=0, then=1),
            default=0,
            output_field=IntegerField()
        )
    ),
    complete_applicant=Sum(
        Case(
            When(is_active=True, profile_completed=True, status=0, then=1),
            default=0,
            output_field=IntegerField()
        )
    ),
    former=Sum(
        Case(
            When(is_active=False, status=2, then=1),
            default=0,
            output_field=IntegerField()
        )
    ),
    accepted=Sum(
        Case(
            When(is_active=False, status=1, then=1),
            default=0,
            output_field=IntegerField()
        )
    )
)

方案对比

  • 原写法:通过annotate生成带统计字段的查询集,再取第一个元素的值,本质是单次查询,但annotate为分组统计设计,用aggregate更适配全局统计场景。
  • aggregate+Count方案:代码最简洁,Django自动生成单次SQL查询,性能最优。
  • Case+Sum方案:逻辑更直观,适合复杂条件的统计场景,同样是单次查询。

所有优化方案都仅产生1次数据库查询,比多次调用count()(产生5次查询)效率更高。

内容的提问来源于stack exchange,提问作者Spirconi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 13:36:37