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
相关产品推荐
相关产品推荐

