Как отфильтровать набор запросов в changelist_view в админке django?

Допустим, у меня есть сайт, на котором пользователи могут добавлять записи через панель администратора. У каждого пользователя есть своя категория, за которую он отвечает (каждая категория имеет редактора, назначенного через ForeingKey/ManyToManyField).

Когда пользователь добавляет Entry, я ограничиваю выбор с помощью EntryAdmin следующим образом:

class EntryAdmin(admin.ModelAdmin):
    (...)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'category':
            if request.user.is_superuser:
                kwargs['queryset'] = Category.objects.all()
            else:
                kwargs['queryset'] = Category.objects.filter(editors=request.user)
            return db_field.formfield(**kwargs)
        return super(EntryAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

Таким образом, я могу ограничить категории, в которые пользователь может добавить запись, и это работает отлично.

Теперь сложная часть: на странице списка изменений/действий записи я хочу показать только те записи, которые принадлежат текущей категории пользователя. Я попытался сделать это, используя этот метод:

    def changelist_view(self, request, extra_context=None):
        if not request.user.is_superuser:
            self.queryset = self.queryset.filter(editors=request.user)

Но я получаю эту ошибку:

AttributeError: объект «функция» не имеет атрибута «фильтр»

Это странно, потому что я думал, что это должен быть типичный QuerySet. В основном такие методы плохо документированы и копаться в тоннах кода Django — не мой любимый вид спорта.

Любые идеи, как я могу достичь своей цели?


person minder    schedule 11.04.2010    source источник


Ответы (1)


Предупреждение. Этот ответ датирован 2010 годом и бесполезен для Django >= 1.8.

queryset — это метод ModelAdmin, который возвращает набор запросов. Вам нужно переопределить его в своем классе EntryAdmin.

def queryset(self, request):
    qs = super(EntryAdmin, self).queryset(request)
    if request.user.is_superuser:
        return qs
    else:
        return qs.filter(editors=request.user)

Изменение набора запросов ограничит количество записей, отображаемых в представлении списка. Вам также необходимо переопределить has_change_permission, чтобы гарантировать, что у пользователя есть разрешение на редактирование объекта на отдельной странице редактирования объекта. Дополнительную информацию см. в следующем сообщении в блоге Джеймса Беннета:

http://www.b-list.org/weblog/2008/dec/24/admin/

person Alasdair    schedule 11.04.2010
comment
QuerySet необходимо отфильтровать по категории. Но есть проблема, когда пользователю назначено более одной категории. Или, может быть, я что-то упускаю. - person minder; 12.04.2010
comment
По крайней мере, в Django 2.2 метод называется get_queryset, а не queryset. - person ge0rg; 05.02.2020
comment
@ge0rg Да, методы были переименован в Django 1.6. Вопросу и ответу почти 10 лет, поэтому они не очень полезны для современных версий Django. - person Alasdair; 05.02.2020
comment
Пример в последней версии документации Django (3.0) выглядит почти так же, за исключением имени метода: ModelAdmin.get_queryset. Итак, я думаю, по крайней мере, эта часть ответа все еще полезна? - person djvg; 17.06.2020