Django ORM Left Join на одну и ту же таблицу

У меня есть пользовательская система разрешений в проекте django, которая может связать любого пользователя с любым конкретным экземпляром модели, чтобы предоставить разрешение на этот объект. Это более сложная задача, но вкратце она сводится к следующему:

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')

Я хочу запросить все разрешения для любого пользователя, которые связаны с тем же объектом(ами) 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 подзапросом [Django-doc] что, вероятно, вы и собираетесь сделать, поэтому:

from django.db.models import Exists, OuterRef

Permission.objects.filter(
    Exists(Permission.objects.filter(
        user_id=12345, content_type_id=OuterRef('content_type_id'), object_id=OuterRef('object_id')
    ))
)

Другим вариантом может быть использование "трюка один-два" с моделью ContentType и работа с:

from django.db.models import F

Permission.objects.filter(
    content_type__permission__user=12345,
    content_type__permission__id__isnull=False,
    content_type__permission__object_id=F('object_id')
)
Вернуться на верх