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