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

如何在Django中筛选同时包含指定两个name的email?

问题描述

假设存在如下Event模型数据:

nameemail
Au1@example.org
Bu1@example.org
Bu1@example.org
Cu2@example.org
Bu3@example.org
Bu3@example.org
Au4@example.org
Bu4@example.org

需求是找出所有**同时关联name为A和B**的email,预期结果为["u1@example.org", "u4@example.org"]。

当前使用的代码无法满足需求,会误将仅关联单个name的重复邮箱(如u3@example.org)纳入结果:

emails = [
    e["email"]
    for e in models.Event.objects.filter(name__in=["A", "B"])
    .values("email")
    .annotate(count=Count("id"))
    .order_by()
    .filter(count__gt=1)
]
问题根源

原代码用Count("id")统计的是该邮箱在A/B筛选条件下的总记录数,而非关联的不同name数量。比如u3@example.org有两条B记录,总记录数为2,满足count__gt=1,但实际上只关联了B,不符合需求。

解决方案

方案1:统计去重后的name数量

使用Count("name", distinct=True)统计每个邮箱关联的不同name数量,筛选数量等于2的邮箱:

emails = [
    e["email"]
    for e in models.Event.objects.filter(name__in=["A", "B"])
    .values("email")
    .annotate(unique_name_count=Count("name", distinct=True))
    .order_by()
    .filter(unique_name_count=2)
]

distinct=True确保每个name只被计数一次,只有同时关联A和B的邮箱,unique_name_count才会等于2,完美排除单个name重复的情况。

方案2:取两次筛选的交集

分别找出关联A和关联B的邮箱集合,取两者的交集:

# 方法1:用集合交集
a_emails = models.Event.objects.filter(name="A").values_list("email", flat=True)
b_emails = models.Event.objects.filter(name="B").values_list("email", flat=True)
emails = list(set(a_emails) & set(b_emails))

# 方法2:用Django QuerySet的intersection(Django 1.11+支持)
emails = list(
    models.Event.objects.filter(name="A").values_list("email", flat=True)
    .intersection(
        models.Event.objects.filter(name="B").values_list("email", flat=True)
    )
)

这种方法逻辑直观,直接筛选同时存在于两个结果集的邮箱,天然避免单个name的干扰。

方案3:分别统计A/B的存在情况

用Case和Count分别统计每个邮箱是否有A和B的记录,筛选两者都存在的邮箱:

from django.db.models import Case, When, IntegerField

emails = [
    e["email"]
    for e in models.Event.objects.values("email")
    .annotate(
        has_a=Count(Case(When(name="A", then=1), output_field=IntegerField())),
        has_b=Count(Case(When(name="B", then=1), output_field=IntegerField()))
    )
    .filter(has_a__gt=0, has_b__gt=0)
]

通过Case标记符合条件的记录,再用Count统计数量,只要has_a和has_b都大于0,说明该邮箱同时关联了A和B。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 07:20:48