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

Django如何对关联同一外键的两个表联合统计去重用户数

实现方案

可以实现该需求,不需要编写大量额外校验逻辑,常用的两种方案如下:

  • 方案1:数据库层面计算(性能最优,适合大数据量场景)
    通过子查询+Union合并两种报销关联的用户,Union默认自动去重,再统计总用户数即可,示例代码如下:
from django.db.models import Count, OuterRef, Subquery

# 构造同一ModelName对象下两种报销的用户ID查询集
mileage_user_ids = MileageClaim.objects.filter(
    your_model_name_id=OuterRef('pk')
).values_list('user_id', flat=True)
expense_user_ids = ExpenseClaim.objects.filter(
    your_model_name_id=OuterRef('pk')
).values_list('user_id', flat=True)

# 合并两个查询集并自动去重
all_unique_user_ids = mileage_user_ids.union(expense_user_ids)

# 注解统计三个字段
queryset = ModelName.objects.annotate(
    mileage_emp_count=Count('mileageclaim__user', distinct=True),
    general_emp_count=Count('expenseclaim__user', distinct=True),
    # 统计合并去重后的总用户数
    total_unique_emp_count=Subquery(
        all_unique_user_ids.annotate(
            total=Count('user_id', distinct=True)
        ).values('total')
    )
)

注:把代码中的your_model_name_id替换为你的ModelName在两个报销表中的外键字段名即可。

  • 方案2:Python层面计算(写法最简单,适合小数据量场景)
    如果你的查询结果数据量不大,不需要在数据库层面完成计算,直接在读取结果时合并两个用户集合去重即可,无需修改原查询逻辑:
# 沿用你原来的查询逻辑
queryset = ModelName.objects.annotate(
    mileage_emp_count=Count('mileageclaim__user', distinct=True),
    general_emp_count=Count('expenseclaim__user', distinct=True)
)

# 遍历计算去重后的总用户数
for item in queryset:
    mileage_users = set(item.mileageclaim.values_list('user_id', flat=True))
    expense_users = set(item.expenseclaim.values_list('user_id', flat=True))
    # 取并集的长度即为去重后的总用户数
    total_unique_count = len(mileage_users | expense_users)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:24:03