django Создание SQL запроса через ORM с не явными связми, возможно ли?

Всем доброго времени суток

Создаю форум с помощью pybb, необходимо добавить дополнительные права доступа для каждого отдельного форума.
Решил использовать для этого django_guardian. Возникла сложность с тем что я не представляю как через ORM можно создавать грамозкие sql запросы без наличия Foreign key между таблицами.

Есть следующие таблицы в базе данных:
image

В django они представленны следующим образом:

# django auth permission model:
class Permission(models.Model):
    name = models.CharField(_('name'), max_length=50)
    content_type = models.ForeignKey(ContentType)
    codename = models.CharField(_('codename'), max_length=100)

# guardian group permission model
class GroupObjectPermissionBase(BaseObjectPermission):
    permission = models.ForeignKey(Permission)
    content_type = models.ForeignKey(ContentType)
    object_pk = models.CharField(_('object ID'), max_length=255)
    content_object = GenericForeignKey(fk_field='object_pk')
    group = models.ForeignKey(Group) # reference to django group

class Forum(models.Model):
    name = models.CharField(_('Name'), max_length=80, default='')
    slug = models.SlugField(default='', unique=True)
    hidden = models.BooleanField(_('Hidden'), blank=False, null=False, default=False)
    headline = models.TextField(_('Headline'), blank=True, null=True)

    class Meta(object):
        permissions = (
           ('view_forum', 'Only view forum'),
    )


Те на уровне SQL таблицы Forum и GroupObjectPermission никак не связанны (более того у них поля «для связи» имеют даже разный тип данных)

Мне надо получить все форумы, для которых группа #1,2,3 имеет запись в таблице GroupObjectPermission с ссылкой на Permission и кодовым словом 'view_forum'.

Либо другими словами — В таблице GroupObjectPermission с group_id = (1,2,3) найти связть с таблицей Permission где codename = 'view_forum' и еще что бы GroupObjectPermission.object_id = Forum.pk

В виде SQL (а то на словах сильно все запутанно):

SELECT * FROM pybb_forum as ff 
    JOIN guardian_groupobjectpermission as gg ON ff.id = gg.object_pk 
    JOIN auth_permission as pp ON gg.permission_id = pp.id 
    WHERE codename = 'view_forum' 
    AND gg.group_id in (1,2,3)
    AND gg.content_type_id = 9


Хочется написать что-то вроде:
Forum.objects.filter(groupobjectpermission__permission__codename='view_forum') но к сожалению django не знает как связать Forum и GroupObjectPeermission.
Реально ли написать такой запрос на django-orm? Через extra?

Заранее спасибо за совет
  • Вопрос задан
  • 4477 просмотров
Пригласить эксперта
Ответы на вопрос 2
cachealot
@cachealot Автор вопроса
Пока писал вопрос в Q&A разобрался в ORM.

Конкретно в моем случае запрос можно переписать c JOIN на WHERE:

SELECT * FROM pybb_forum as ff,guardian_groupobjectpermission as gg, auth_permission as pp 
     WHERE codename = 'view_forum'      
     AND gg.group_id in (1,2,3)     
     AND gg.content_type_id = 9 
     AND  ff.id = gg.object_pk 
     AND gg.permission_id = pp.id;


a WHERE уже довольно просто подставить в objects.extra:

Forum.objects.extra(
    tables = ['guardian_groupobjectpermission', 'auth_permission'],
    where = [""" codename = "view_forum"
    AND guardian_groupobjectpermission.group_id in (1,2,3)
    AND guardian_groupobjectpermission.content_type_id = 9
    AND pybb_forum.id = guardian_groupobjectpermission.object_pk
    AND guardian_groupobjectpermission.permission_id = auth_permission.id
    """]
)


Единственная проблема — совсем пропала читабельность такого запроса.
Ответ написан
Комментировать
Bteam
@Bteam

Вам же выше ответили, что в доке это всё есть. Или вам нужно чтоб за вас сделали? Ну вот на первый раз я за вас сделал, но вам должно быть стыдно. Добавьте к модели Forum:


groupobjectpermission = GenericRelation(GroupObjectPermissionBase, 
                                 content_type_field='content_type',
                                 object_id_field='object_pk')
И тогда будет работать как вы и хотели - Forum.objects.filter(groupobjectpermission__permission__codename='view_forum')

Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы