Django ORM 左连接到同一个 table

Django ORM Left Join onto same table

我在 Django 项目中有一个自定义权限系统,可以 link 任何用户向任何特定模型实例授予对该对象的权限。它比这更复杂,但归结为:

class Permission(models.Model):
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

我想查询任何用户的所有权限,这些权限被link编辑到特定用户已被授予权限的相同content_object。换句话说,有问题的用户想看看还有谁对他们所做的任何相同对象具有权限。

在 SQL 中,以下是诀窍:

SELECT 
    perm1.* 
FROM app_permission perm1 
LEFT JOIN app_permission perm2 
    ON perm2.user_id = 12345
    AND perm1.content_type_id = perm2.content_type_id 
    AND perm1.object_id = perm2.object_id 
WHERE perm2.id IS NOT NULL;

是否可以在 django ORM 中实现这一点?

您可以使用 Exists subquery [Django-doc] 这可能是您打算做的,所以:

from django.db.models import <strong>Exists, OuterRef</strong>

Permission.objects.filter(
    Exists(Permission.objects.filter(
        user_id=12345<strong>, content_type_id=OuterRef('content_type_id'), object_id=OuterRef('object_id')</strong>
    ))
)

另一种选择是对 ContentType 模型使用“一二技巧”并使用:

from django.db.models import <strong>F</strong>

Permission.objects.filter(
    content_type__permission__user=12345,
    content_type__permission__id__isnull=False,
    <strong>content_type__permission__object_id=F('object_id')</strong>
)