admin.py django отфильтровать по permissions вывод actions, filter и list_display.
Давайте представим ситуацию когда нужно создать узкоспециализированную учётную запись в django которой будут доступны лишь ограниченный функционал административной панели.
Во первых используя штатный механизм django мы создадим группу в которую мы добавим только нужные разрешения для пользователей входящих в эту группу.
А далее на основании этих разрешений мы сможем дополнительно кастомизировать функционал и вывод информации в админке для таких пользователей.
сначала соберём нужную информацию, для этого заходим в окружение вашего проекта django
находясь в нужном месте пути, вашего проекта выполняем
source venv/bin/activate python manage.py shell
вводим построчно, соблюдая правильные отступы
☯
Terminal:
⌕
≡
✕
from django.contrib.auth.models import Group #если у вас кастомный юзер, как у меня, в качестве логина только с email без имени(как такого сделать в другой статье) или #from users.models import User from users.models import CustomUser as User user = User.objects.get(email='yourmail@mail.com') groups = user.groups.all() for group in groups: group_name = group.name group_id = group.id print(group_name) print(group_id) #Теперь в оболочке, импортируйте модель Permission из модуля django.contrib.auth.models: from django.contrib.auth.models import Permission permissions = Permission.objects.filter(content_type__app_label='your_app') for permission in permissions: print(permission.codename)
Так мы получим все имена групп в которых состоит этот пользователь и узнаем нужный id группы, которую мы планируем ограничить. либо можно будет ограничивать пользователя и на основании отстуствия определённых прав, узнать какие права вообще существуют можно так.
А также вывели кодовые имена (permission_codename) доступных разрешений для указанного приложения. Обратите внимание, что вы должны заменить 'your_app' на фактическое имя вашего приложения.
Давайте рассмотрим сперва ограничение по имени доступных разрешений, а потом рассмотрим по id группы, но принцип один и тот же.
В данном случае я хочу убрать доступ к некоторым из actions, в админке, для такого набора разрешений.
допустим в нашем admin.py есть модель которую мы выводим в админке
☯
Terminal:
⌕
≡
✕
from django.contrib import admin from .models import YourModel1, YourModel2 #например одно из действий def dublicate_ad(modeladmin, request, queryset): # клонирование выбранных объектов модели for ad in queryset: ad.pk = None ad.save() dublicate_ad.short_description = "Дублировать объект" #Создаём новый класс CustomModelAdmin, наследуемый от ModelAdmin, и переопределим метод get_actions(), #для определения списка действий, доступных пользователю: class CustomModelAdmin(admin.ModelAdmin): def get_actions(self, request): actions = super().get_actions(request) #создаём два списка, пустой и список с именами действий которые мы желаем скрыть actions_to_remove = [] hidden_actions = ['dublicate_ad','render_to_pdf_ALL','export_admin_action'] #наполняем пустой список теми действиями, которые попадают в это условие, т.е. находятся в списке скрываемых и при этом у пользователя отсутствуют нужные права, которые мы явно тут укажем for action in actions: if not request.user.has_perm('your_app.change_title') and action in hidden_actions: actions_to_remove.append(action) #теперь на основании этого созданного списка удаляем действия которые находятся в основном списке действий. так нужно делать чтобы итерируемый массив не менялся в количестве элементов по ходу итераций в этом цикле... for action in actions_to_remove: del actions[action] return actions #Зарегистрируйте модели с использованием нового класса администратора в функции admin.site.register(): admin.site.register(YourModel1, CustomModelAdmin) admin.site.register(YourModel2, CustomModelAdmin)
Мы идём таким путём, чтобы использовать массив request с нужными нам данными
Фактически метод get_actions() вызывается автоматически во время отображения списка действий (actions) в административной панели Django.
Теперь, давайте ещё кое-что сделаем. Мы можем добавить в отображаемые в админке, связь "один ко многим" (ForeignKey), чтобы вывести поле, связанное с помощью этой связи, в административной панели с помощью атрибута list_display в классе ModelAdmin.
Предположим, у вас есть модель Zakaz, имеющая внешний ключ foreign_key на модель Investor.
Чтобы вывести поле, связанное с Innvestor, с помощью list_display, вам нужно сначала определить метод в классе ModelAdmin, который будет возвращать значение этого поля. Затем это поле можно добавить в list_display.
☯
Terminal:
⌕
≡
✕
#например используем такую функцию проверки наличия id в списке объектов, чтобы по id группы сделать нужное действие def checkID(id,objects): result = False for obj in objects: if id == obj.id: result = True break return result class CustomModelAdmin(admin.ModelAdmin): ... ... ... list_display = ('pk','cert_tag','investor','investor_tel') #допустим мы решили разрешить видеть такое поле определённой группе у которой id=2, тогда проверим если у текущего пользователя есть такая группа def investor_tel(self, obj): if checkID(2,request.user.groups.all()): return obj.investor.phone else return 'нет прав, чтобы это видеть' investor_tel.short_description = 'Телефон пользователя' # Опционально, для отображения пользовательского заголовка в колонке
аналогичным образом если у пользователя есть разрешения или он состоит в группе с id 2 покажем разные фильтры
☯
Terminal:
⌕
≡
✕
def checkID(id,objects): result = False for obj in objects: if id == obj.id: result = True break return result class CustomModelAdmin(admin.ModelAdmin): ... ... ... # просто скрыть один или несколько фильтров в зависимости от разрешения пользователя def get_list_filter(self, request): if request.user.has_perm('shop.can_change_filter') or checkID(2,request.user.groups.all()): # Если у пользователя есть разрешение "can_change_filter", показать такие фильтры return ('resendcert','participation','investor',AggregatorFilter,'status','status_pay') else: # иначе такие return ('email_send','place','date_exec','date_order'',')
как вы уже наверное поняли мы переопределяем и используем существующие методы, которые автоматически вызываются в django get_list_filter, get_actions и таким образом решили свои вопросы.
-
- Roman Sakhno
Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.