自己加入 Django

Self join in Django

要对以下 table 使用自联接执行查询:

> select * from test_users
id  email
--- -----------
1   "a@abc.com"
2   "a@abc.com"
3   "b@abc.com"

我可以使用 SQL:

> select u1.id u1id, u2.id u2id from test_users u1 inner join test_users u2 on u1.email=u2.email and u1.id !=u2.id
u1id   u2id
-----  ------
1      2
2      1

问题:

  1. 如何在 Django ORM 中编写此代码?
  2. 如果我想删除重复项以便在上面的示例中只得到 1 行,我如何在 Django 中实现它?

您可以检索 Users,其中有另一个项目的主键大于(或小于)具有 Exists subquery [Django-doc] 的用户的主键:

from django.db.models import Exists, OuterRef

Users.objects.filter(
    Exists(
        User.objects.filter(
            <strong>pk__gt=OuterRef('pk')</strong>,
            <strong>email=OuterRef('email')</strong>
        )
    )
)

如果您因此对这些调用 .delete(),您将删除所有 User,因为存在另一个具有更大主键的 Users 对象。

之前,应该将 Exists 子查询移动到 .annotate(…) 子句,然后过滤:

from django.db.models import Exists, OuterRef

Users.objects<b>.annotate(</b>
    <b>has_other=</b>Exists(
        User.objects.filter(
            <strong>pk__gt=OuterRef('pk')</strong>,
            <strong>email=OuterRef('email')</strong>
        )
    )
<b>).filter(has_other=True)</b>