SQLAlchemy и сложные запросы
Я должен реализовать ACL для существующего приложения.
Поэтому я добавил в базу данных таблицу user, group и groupmembers.
Я определил отношение ManyToMany между пользователем и группой через членов таблицы ассоциации.
Чтобы защитить некоторые ресурсы приложения (элемент...), я добавил дополнительную таблицу ассоциации auth_items, которую следует использовать в качестве таблицы ассоциации для отношений ManyToMany между группами / пользователями и конкретным элементом.
Элемент имеет следующие столбцы:
- user_id -> таблица пользователей
- group_id -> групповая таблица
- item_id -> таблица элементов
как минимум один из столбцов user_id и group_id. Таким образом, можно определить доступ для группы или пользователя к определенному элементу.
Я использовал AssociationProxy для определения отношений между пользователями / группами и элементами.
Теперь я хочу отобразить все элементы, к которым у пользователя есть доступ, и мне действительно трудно это делать. Используются следующие критерии:
- Все элементы, принадлежащие пользователю, должны быть показаны (item.owner_id = user.id)
- Все публичные предметы должны быть показаны (item.access = public)
- Должны быть показаны все элементы, к которым у пользователя есть доступ (auth_item.user_id = user.id)
- Все элементы, к которым имеет доступ группа пользователей, должны быть показаны.
Первые три критерия довольно просты, но мне трудно справиться с четвертым.
Вот мой подход:
clause = and_(item.access == 'public')
if user is not None:
clause = or_(clause,item.owner == user,item.users.contains(user),item.groups.contains(group for group in user.groups))
Третий критерий дает ошибку.
item.groups.contains(group for group in user.groups)
Я на самом деле не уверен, что это хороший подход вообще.
Каков наилучший подход при фильтрации многих отношений?
Как я могу отфильтровать множество отношений на основе другого списка / отношения?
Кстати, я использую последнюю версию sqlalchemy (6.0) и эликсира
Спасибо за любые идеи.
1 ответ
contains()
Метод для проверки одного элемента. Предполагая, что ваша групповая таблица сопоставлена с Group
класс попробуйте следующее:
item.groups.any(Group.id.in_([group.id for group in user.groups])